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

Latest dev sync

This commit is contained in:
marzavec 2022-06-22 11:32:51 -05:00
parent 39b47554b8
commit 2bbb507f01
180 changed files with 50855 additions and 4416 deletions

View File

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

3
.eslintignore Normal file
View File

@ -0,0 +1,3 @@
/test/*.js
/client/*
/documentation/*

33
.eslintrc.cjs Normal file
View File

@ -0,0 +1,33 @@
module.exports = {
env: {
es2021: true,
node: true,
},
extends: [
'airbnb-base',
],
parserOptions: {
ecmaVersion: 'latest',
sourceType: 'module',
},
rules: {
"no-console": 0,
"no-param-reassign": [
"error",
{
"props": false,
}
],
"import/extensions": [
"error",
"ignorePackages",
{
js: "always",
jsx: "always",
ts: "always",
tsx: "always",
mjs: "always",
}
]
},
};

View File

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

85
.gitignore vendored
View File

@ -4,6 +4,11 @@ logs
npm-debug.log* npm-debug.log*
yarn-debug.log* yarn-debug.log*
yarn-error.log* yarn-error.log*
lerna-debug.log*
.pnpm-debug.log*
# Diagnostic reports (https://nodejs.org/api/report.html)
report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json
# Runtime data # Runtime data
pids pids
@ -15,12 +20,13 @@ pids
lib-cov lib-cov
# Coverage directory used by tools like istanbul # Coverage directory used by tools like istanbul
coverage .coverage
*.lcov
# nyc test coverage # nyc test coverage
.nyc_output .nyc_output
# Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) # Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files)
.grunt .grunt
# Bower dependency directory (https://bower.io/) # Bower dependency directory (https://bower.io/)
@ -36,8 +42,11 @@ build/Release
node_modules/ node_modules/
jspm_packages/ jspm_packages/
# Typescript v1 declaration files # Snowpack dependency directory (https://snowpack.dev/)
typings/ web_modules/
# TypeScript cache
*.tsbuildinfo
# Optional npm cache directory # Optional npm cache directory
.npm .npm
@ -45,6 +54,15 @@ typings/
# Optional eslint cache # Optional eslint cache
.eslintcache .eslintcache
# Optional stylelint cache
.stylelintcache
# Microbundle cache
.rpt2_cache/
.rts2_cache_cjs/
.rts2_cache_es/
.rts2_cache_umd/
# Optional REPL history # Optional REPL history
.node_repl_history .node_repl_history
@ -54,10 +72,63 @@ typings/
# Yarn Integrity file # Yarn Integrity file
.yarn-integrity .yarn-integrity
# dotenv environment variables file # dotenv environment variable files
.env .env
.env.development.local
.env.test.local
.env.production.local
.env.local
# next.js build output # parcel-bundler cache (https://parceljs.org/)
.cache
.parcel-cache
# Next.js build output
.next .next
out
server/config/ # Nuxt.js build / generate output
.nuxt
dist
# Gatsby files
.cache/
# Comment in the public line in if your project uses Gatsby and not Next.js
# https://nextjs.org/blog/next-9-1#public-directory-support
# public
# vuepress build output
.vuepress/dist
# vuepress v2.x temp and cache directory
.temp
.cache
# Docusaurus cache and generated files
.docusaurus
# Serverless directories
.serverless/
# FuseBox cache
.fusebox/
# DynamoDB Local files
.dynamodb/
# TernJS port file
.tern-port
# Stores VSCode versions used for testing VSCode extensions
.vscode-test
# yarn v2
.yarn/cache
.yarn/unplugged
.yarn/build-state.yml
.yarn/install-state.gz
.pnp.*
session.key
salt.key
config.json

1
.hcserver.json Normal file
View File

@ -0,0 +1 @@
{"modulesPath":"./commands","websocketPort":"6060","rateLimit":{"halflife":"30000","threshold":"25"},"pulseSpeed":"16000"}

29
.nycrc Normal file
View File

@ -0,0 +1,29 @@
{
"check-coverage": true,
"per-file": true,
"lines": 80,
"statements": 80,
"functions": 80,
"branches": 80,
"include": [
"commands/**/*.js"
],
"exclude": [
"commands/**/*.spec.js"
],
"ignore-class-method": "methodToIgnore",
"reporter": [
"html",
"lcov",
"text",
"text-summary"
],
"require": [
"dotenv/config"
],
"extension": [],
"cache": true,
"all": true,
"temp-dir": "",
"report-dir": "./.coverage"
}

View File

@ -1,147 +0,0 @@
# Changelog
All notable changes to this project will be documented in this file.
## [Unreleased]
## [2.1.93 pre 2.2] - 2020-03-12
### Added
- (Source) `./pm2.config.js` PM2 ecosystem config handling both http-server and the websocket
- (Source) NPM new commands:
- "start": Starts or reloads the dev environment
- "stop": Stops and clears the dev environment
- "logs": Show / watch http & websocket logs for errors and events
- "clear": Clear all logged data
- "status": Show status of http and websocket
- "refresh": Clears logged data and stops http and websocket
- (Server) Numeric user levels / UAC, related to issue #86
- (Server) `join` module password property, related to V2 protocol update
- (Server) `users` array to `onlineSet` structure, related to V2 protocol update
- (Server) `session` module, related to V2 protocol update
- (Server) `/move` chat hook to `move` module
### Removed
- (Source) `./clientSource/` directory
### Changed
- (Server) Minor bug fixes
- (Server) Increased module abstraction to remove duplicate code (thanks @MinusGix)
## [2.1.92 pre 2.2] - 2019-11-06
### Added
- (Server) `./server/src/utility/` directory
- (Server) `Constants.js` class in `utility`
- (Server) `esm` module to transpile ES6
### Changed
- (Server) Changed ES5 styling to ES6
- (Server) And improved source comments
- (Server) Minor code format changes
- (Server) Updated all dependencies (be sure to update your local copy with the new packages)
## [2.1.91 pre 2.2] - 2019-08-17
### Added
- (Client) Markdown engine
- (Client) Imgur based image posting (through markdown)
### Changed
- (Client) Removed cloudflare references making hack.chat self-hosted again
- (Client) The way messages are pushed, closing an xss vuln in PRs 985dd6f and 9fcb235
- (Client) Side bar layout
- (Client) Fixed some options not storing
- (Client) Fixed firefox drop down menu bug
- (Client) Updated Katex lib
### Stretched
- The term "minimal"
## [2.1.9 pre 2.2] - 2019-03-18
### Changed
- Configuration script setup, making it more portable/sane
- Refactored naming scheme and entry point
### Removed
- Configuration setup from `./serverLib/ConfigManager`
- Unused feature allowing command modules to add to the configuration/setup process
- `deasync` dependency
## [2.1.9] - 2019-02-21
### Added
- `./server/src/commands/core/emote.js` module to provide action text
- `./server/src/core/server.js` priorities to command hooking
- Priority levels to all command modules
- `./server/src/commands/core/chat.js` Unknown '/' commands will now return a warning
- `./server/src/commands/internal/legacylayer.js` to provide compatibility to legacy connections
### Changed
- Updated all libraries to latest
- `./server/src/core/server.js` Removed unneeded function bindings
- `./server/src/core/server.js` Hook function layout
- `./server/src/managers/config.js` Documentation wording
## [2.1.0] - 2018-09-29
### Added
- Module hook framework, isolating modules and making them truly drop-to-install
- `./server/src/commands/core/whisper.js` module to send in-channel private messages, `/whisper` hook
- `muzzle` and `mute` aliases to `./server/src/commands/mod/dumb.js`
- `unmuzzle` and `unmute` aliases to `./server/src/commands/mod/speak.js`
- `./server/src/commands/admin/removemod.js` module to remove mods
- `./server/src/commands/mod/unbanall.js` module to clear all bans and ratelimiting
### Changed
- Further code cleanup on all modules
- Adjusted `ipSalt` entropy
- `./server/src/commands/core/help.js` output is now helpful, added `/help` hook
- `./server/src/commands/core/chat.js` added `/myhash` and `/me` hooks
- `./server/src/commands/core/morestats.js` added `/stats` hook
## [2.0.3] - 2018-06-03
### Added
- `./server/src/commands/mod/dumb.js` module for server-wide shadow muting
- `./server/src/commands/mod/speak.js` module unmuting
- `./server/src/commands/internal/socketreply.js` module to route warning to clients
- `./server/src/commands/core/ping.js` module to prevent `didYouMean` errors on legacy sources
### Changed
- Moved `disconnect.js` into servers internal modules directory
- Restructured `server.js` and `commands.js`, removing hardcoded protocol use
## [2.0.2] - 2018-05-19
### Added
- `./documentation/DOCUMENTATION.md` document which gives overview of the applications protocol
- `./documentation/DEPLOY.md` document which gives overview of deploying the server live
- `./LICENSE` License file
- Code highlighting, triggered with #
### Changed
- `README.md` wording and layout
### Removed
- Unneeded `use strict`
## [2.0.1] - 2018-04-18
### Added
- `users-kicked` tracking to `morestats` command
- Server-side ping interval
- `move` command to change channels without reconnecting
- `disconnect` command module to free core server from protocol dependency
- `changenick` command to change client nick without reconnecting
### Changed
- Filter object of the `findSockets` function now accepts more complex parameters, including functions and arrays
- `kick` command now accepts an array as the `nick` argument allowing multiple simultaneous kicks
- `join` command now takes advantage of the new filter object
- Core server disconnect handler now calls the `disconnect` module instead of broadcasting hard coded `onlineRemove`
### Removed
- Client-side ping interval
## [2.0.0] - 2018-04-12
### Added
- CHANGELOG.md
- `index.html` files to `katex` directories
### Changed
- Updated client html KaTeX libraries to v0.9.0
### Removed
- Uneeded files under `katex` directories

26
LICENSE
View File

@ -1,13 +1,21 @@
DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE MIT License
Version 2, December 2004
Copyright (C) 2004 Sam Hocevar <sam@hocevar.net> Copyright (c) 2022 marzavec
Everyone is permitted to copy and distribute verbatim or modified Permission is hereby granted, free of charge, to any person obtaining a copy
copies of this license document, and changing it is allowed as long of this software and associated documentation files (the "Software"), to deal
as the name is changed. in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE The above copyright notice and this permission notice shall be included in all
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION copies or substantial portions of the Software.
0. You just DO WHAT THE FUCK YOU WANT TO. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

View File

@ -4,14 +4,14 @@
A list of software developed for the hack.chat framework can be found at the [3rd party software list](https://github.com/hack-chat/3rd-party-software-list) repository. This includes bots, clients, docker containers, etc. A list of software developed for the hack.chat framework can be found at the [3rd party software list](https://github.com/hack-chat/3rd-party-software-list) repository. This includes bots, clients, docker containers, etc.
This is a backwards compatible continuation of the [work by Andrew Belt](https://github.com/AndrewBelt/hack.chat). The server code has been updated to ES6 along with several new features including new commands and hot-reload of the commands/protocol. There is also [documentation](documentation/DOCUMENTATION.md) and a [changelog](CHANGELOG.md). This is a backwards compatible continuation of the [work by Andrew Belt](https://github.com/AndrewBelt/hack.chat). The server code has been updated to ES6 along with several new features including new commands and hot-reload of the commands/protocol. There is also [documentation](documentation/index.html).
# Installation # Installation
## Prerequisites ## Prerequisites
- [node.js 8.10.0](https://nodejs.org/en/download/package-manager/#windows) or higher - [node.js v16.14.0](https://nodejs.org/) or higher
- [npm 5.7.1](https://nodejs.org/en/download/package-manager/#windows) or higher - [npm 8.5.4](https://nodejs.org/) or higher
## Developer Installation ## Developer Installation
@ -20,19 +20,14 @@ This is a backwards compatible continuation of the [work by Andrew Belt](https:/
1. Install the dependencies: `npm install` 1. Install the dependencies: `npm install`
1. Launch: `npm start` 1. Launch: `npm start`
If you change the `websocketPort` option during the config setup then these changes will need to be reflected on [line 60 of client.js](https://github.com/hack-chat/main/blob/master/client/client.js#L60).
## Live Deployment Installation ## Live Deployment Installation
See [DEPLOY.md](documentation/DEPLOY.md) See [DEPLOY.md](documentation/DEPLOY.md)
# Contributing # Contributing
- If you are modifying commands, make sure it is backwards compatible with the legacy client and you update the documentation accordingly.
- Use [the template](documentation/templateCommand.js) to learn how to create new commands.
- Use two space indents. - Use two space indents.
- Name files in camelCase. - Name files in camelCase.
- Scripts that do not default to strict mode (such as modules) must use the `'use strict'` directive.
# Credits # Credits
@ -41,10 +36,10 @@ See [DEPLOY.md](documentation/DEPLOY.md)
* [**Neel Kamath**](https://github.com/neelkamath) - *Base Documentation* * [**Neel Kamath**](https://github.com/neelkamath) - *Base Documentation*
* [**Carlos Villavicencio**](https://github.com/po5i) - *Syntax Highlighting Integration* * [**Carlos Villavicencio**](https://github.com/po5i) - *Syntax Highlighting Integration*
* [**OpSimple**](https://github.com/OpSimple) - *Modules Added: dumb.js & speak.js* * [**OpSimple**](https://github.com/OpSimple) - *Modules Added: dumb.js & speak.js*
* Andrew Belt, https://github.com/AndrewBelt, for original base work * [**Andrew Belt**](https://github.com/AndrewBelt), for original base work
* [wwandrew](https://github.com/wwandrew), for finding server flaws (including attack vectors) and submitting ~~___incredibly detailed___~~ bug reports * [**wwandrew**](https://github.com/wwandrew), for finding server flaws (including attack vectors) and submitting ~~___incredibly detailed___~~ bug reports
* [Everyone else](https://github.com/hack-chat/main/graphs/contributors) who participated in this project. * [**Everyone else**](https://github.com/hack-chat/main/graphs/contributors) who participated in this project.
# License # License
This project is licensed under the [WTFPL License](LICENSE). This project is licensed under the [MIT License](LICENSE).

View File

@ -1,15 +1,24 @@
/* /**
Description: Adds the target trip to the mod list then elevates the uType * @author Marzavec ( https://github.com/marzavec )
*/ * @summary Create a new mod trip
* @version 1.0.0
* @description Adds target trip to the config as a mod and upgrades the socket type
* @module addmod
*/
import { import {
isAdmin, isAdmin,
isModerator, isModerator,
levels, levels,
getUserDetails, getUserDetails,
} from '../utility/_UAC'; } from '../utility/_UAC.js';
// module main /**
* Executes when invoked by a remote client
* @param {Object} env - Enviroment object with references to core, server, socket & payload
* @public
* @return {void}
*/
export async function run({ export async function run({
core, server, socket, payload, core, server, socket, payload,
}) { }) {
@ -19,7 +28,7 @@ export async function run({
} }
// add new trip to config // add new trip to config
core.config.mods.push({ trip: payload.trip }); core.appConfig.data.globalMods.push({ trip: payload.trip });
// find targets current connections // find targets current connections
const newMod = server.findSockets({ trip: payload.trip }); const newMod = server.findSockets({ trip: payload.trip });
@ -35,7 +44,7 @@ export async function run({
}; };
for (let i = 0, l = newMod.length; i < l; i += 1) { for (let i = 0, l = newMod.length; i < l; i += 1) {
// upgrade privilages // upgrade privileges
newMod[i].uType = 'mod'; // @todo use legacyLevelToLabel from _LegacyFunctions.js newMod[i].uType = 'mod'; // @todo use legacyLevelToLabel from _LegacyFunctions.js
newMod[i].level = levels.moderator; newMod[i].level = levels.moderator;
@ -73,9 +82,26 @@ export async function run({
return true; return true;
} }
/**
* The following payload properties are required to invoke this module:
* "trip"
* @public
* @typedef {Array} addmod/requiredData
*/
export const requiredData = ['trip']; export const requiredData = ['trip'];
/**
* Module meta information
* @public
* @typedef {Object} addmod/info
* @property {string} name - Module command name
* @property {string} category - Module category name
* @property {string} description - Information about module
* @property {string} usage - Information about module usage
*/
export const info = { export const info = {
name: 'addmod', name: 'addmod',
category: 'admin',
description: 'Adds target trip to the config as a mod and upgrades the socket type', description: 'Adds target trip to the config as a mod and upgrades the socket type',
usage: ` usage: `
API: { cmd: 'addmod', trip: '<target trip>' }`, API: { cmd: 'addmod', trip: '<target trip>' }`,

View File

@ -2,15 +2,24 @@
/* eslint no-restricted-syntax: 0 */ /* eslint no-restricted-syntax: 0 */
/* eslint guard-for-in: 0 */ /* eslint guard-for-in: 0 */
/* /**
Description: Outputs all current channels and their user nicks * @author Marzavec ( https://github.com/marzavec )
*/ * @summary Show users and channels
* @version 1.0.0
* @description Outputs all current channels and sockets in those channels
* @module listusers
*/
import { import {
isAdmin, isAdmin,
} from '../utility/_UAC'; } from '../utility/_UAC.js';
// module main /**
* Executes when invoked by a remote client
* @param {Object} env - Enviroment object with references to core, server, socket & payload
* @public
* @return {void}
*/
export async function run({ server, socket }) { export async function run({ server, socket }) {
// increase rate limit chance and ignore if not admin // increase rate limit chance and ignore if not admin
if (!isAdmin(socket.level)) { if (!isAdmin(socket.level)) {
@ -50,8 +59,18 @@ export async function run({ server, socket }) {
return true; return true;
} }
/**
* Module meta information
* @public
* @typedef {Object} listusers/info
* @property {string} name - Module command name
* @property {string} category - Module category name
* @property {string} description - Information about module
* @property {string} usage - Information about module usage
*/
export const info = { export const info = {
name: 'listusers', name: 'listusers',
category: 'admin',
description: 'Outputs all current channels and sockets in those channels', description: 'Outputs all current channels and sockets in those channels',
usage: ` usage: `
API: { cmd: 'listusers' }`, API: { cmd: 'listusers' }`,

View File

@ -1,13 +1,22 @@
/* /**
Description: Clears and resets the command modules, outputting any errors * @author Marzavec ( https://github.com/marzavec )
*/ * @summary Refresh modules
* @version 1.0.0
* @description Allows a remote user to clear and re-import the server command modules
* @module reload
*/
import { import {
isAdmin, isAdmin,
isModerator, isModerator,
} from '../utility/_UAC'; } from '../utility/_UAC.js';
// module main /**
* Executes when invoked by a remote client
* @param {Object} env - Enviroment object with references to core, server, socket & payload
* @public
* @return {void}
*/
export async function run({ export async function run({
core, server, socket, payload, core, server, socket, payload,
}) { }) {
@ -17,8 +26,7 @@ export async function run({
} }
// do command reload and store results // do command reload and store results
let loadResult = core.dynamicImports.reloadDirCache(); let loadResult = await core.commands.reloadCommands();
loadResult += core.commands.loadCommands();
// clear and rebuild all module hooks // clear and rebuild all module hooks
server.loadHooks(); server.loadHooks();
@ -45,9 +53,19 @@ export async function run({
return true; return true;
} }
/**
* Module meta information
* @public
* @typedef {Object} reload/info
* @property {string} name - Module command name
* @property {string} category - Module category name
* @property {string} description - Information about module
* @property {string} usage - Information about module usage
*/
export const info = { export const info = {
name: 'reload', name: 'reload',
description: '(Re)loads any new commands into memory, outputs errors if any', category: 'admin',
description: 'Allows a remote user to clear and re-import the server command modules',
usage: ` usage: `
API: { cmd: 'reload', reason: '<optional reason append>' }`, API: { cmd: 'reload', reason: '<optional reason append>' }`,
}; };

View File

@ -1,15 +1,24 @@
/* /**
Description: Removes target trip from the config as a mod and downgrades the socket type * @author Marzavec ( https://github.com/marzavec )
*/ * @summary Removes a mod
* @version 1.0.0
* @description Removes target trip from the config as a mod and downgrades the socket type
* @module removemod
*/
import { import {
isAdmin, isAdmin,
isModerator, isModerator,
levels, levels,
getUserDetails, getUserDetails,
} from '../utility/_UAC'; } from '../utility/_UAC.js';
// module main /**
* Executes when invoked by a remote client
* @param {Object} env - Enviroment object with references to core, server, socket & payload
* @public
* @return {void}
*/
export async function run({ export async function run({
core, server, socket, payload, core, server, socket, payload,
}) { }) {
@ -20,7 +29,9 @@ export async function run({
// remove trip from config // remove trip from config
// eslint-disable-next-line no-param-reassign // eslint-disable-next-line no-param-reassign
core.config.mods = core.config.mods.filter((mod) => mod.trip !== payload.trip); core.appConfig.data.globalMods = core.appConfig.data.globalMods.filter(
(mod) => mod.trip !== payload.trip,
);
// find targets current connections // find targets current connections
const targetMod = server.findSockets({ trip: payload.trip }); const targetMod = server.findSockets({ trip: payload.trip });
@ -36,8 +47,8 @@ export async function run({
}; };
for (let i = 0, l = targetMod.length; i < l; i += 1) { for (let i = 0, l = targetMod.length; i < l; i += 1) {
// downgrade privilages // downgrade privileges
targetMod[i].uType = 'user'; targetMod[i].uType = 'user'; /* @legacy */
targetMod[i].level = levels.default; targetMod[i].level = levels.default;
// inform ex-mod // inform ex-mod
@ -76,9 +87,26 @@ export async function run({
return true; return true;
} }
/**
* The following payload properties are required to invoke this module:
* "trip"
* @public
* @typedef {Array} removemod/requiredData
*/
export const requiredData = ['trip']; export const requiredData = ['trip'];
/**
* Module meta information
* @public
* @typedef {Object} removemod/info
* @property {string} name - Module command name
* @property {string} category - Module category name
* @property {string} description - Information about module
* @property {string} usage - Information about module usage
*/
export const info = { export const info = {
name: 'removemod', name: 'removemod',
category: 'admin',
description: 'Removes target trip from the config as a mod and downgrades the socket type', description: 'Removes target trip from the config as a mod and downgrades the socket type',
usage: ` usage: `
API: { cmd: 'removemod', trip: '<target trip>' }`, API: { cmd: 'removemod', trip: '<target trip>' }`,

View File

@ -1,13 +1,22 @@
/* /**
Description: Writes the current config to disk * @author Marzavec ( https://github.com/marzavec )
*/ * @summary Saves the config
* @version 1.0.0
* @description Writes the current config to disk
* @module saveconfig
*/
import { import {
isAdmin, isAdmin,
isModerator, isModerator,
} from '../utility/_UAC'; } from '../utility/_UAC.js';
// module main /**
* Executes when invoked by a remote client
* @param {Object} env - Enviroment object with references to core, server, socket & payload
* @public
* @return {void}
*/
export async function run({ core, server, socket }) { export async function run({ core, server, socket }) {
// increase rate limit chance and ignore if not admin // increase rate limit chance and ignore if not admin
if (!isAdmin(socket.level)) { if (!isAdmin(socket.level)) {
@ -15,7 +24,9 @@ export async function run({ core, server, socket }) {
} }
// attempt save, notify of failure // attempt save, notify of failure
if (!core.configManager.save()) { try {
await core.appConfig.write();
} catch (err) {
return server.reply({ return server.reply({
cmd: 'warn', // @todo Add numeric error code as `id` cmd: 'warn', // @todo Add numeric error code as `id`
text: 'Failed to save config, check logs.', text: 'Failed to save config, check logs.',
@ -33,8 +44,18 @@ export async function run({ core, server, socket }) {
return true; return true;
} }
/**
* Module meta information
* @public
* @typedef {Object} saveconfig/info
* @property {string} name - Module command name
* @property {string} category - Module category name
* @property {string} description - Information about module
* @property {string} usage - Information about module usage
*/
export const info = { export const info = {
name: 'saveconfig', name: 'saveconfig',
category: 'admin',
description: 'Writes the current config to disk', description: 'Writes the current config to disk',
usage: ` usage: `
API: { cmd: 'saveconfig' }`, API: { cmd: 'saveconfig' }`,

View File

@ -1,12 +1,21 @@
/* /**
Description: Emmits a server-wide message as `info` * @author Marzavec ( https://github.com/marzavec )
*/ * @summary Emit text everywhere
* @version 1.0.0
* @description Displays passed text to every client connected
* @module shout
*/
import { import {
isAdmin, isAdmin,
} from '../utility/_UAC'; } from '../utility/_UAC.js';
// module main /**
* Executes when invoked by a remote client
* @param {Object} env - Enviroment object with references to core, server, socket & payload
* @public
* @return {void}
*/
export async function run({ server, socket, payload }) { export async function run({ server, socket, payload }) {
// increase rate limit chance and ignore if not admin // increase rate limit chance and ignore if not admin
if (!isAdmin(socket.level)) { if (!isAdmin(socket.level)) {
@ -23,9 +32,26 @@ export async function run({ server, socket, payload }) {
return true; return true;
} }
/**
* The following payload properties are required to invoke this module:
* "text"
* @public
* @typedef {Array} shout/requiredData
*/
export const requiredData = ['text']; export const requiredData = ['text'];
/**
* Module meta information
* @public
* @typedef {Object} shout/info
* @property {string} name - Module command name
* @property {string} category - Module category name
* @property {string} description - Information about module
* @property {string} usage - Information about module usage
*/
export const info = { export const info = {
name: 'shout', name: 'shout',
category: 'admin',
description: 'Displays passed text to every client connected', description: 'Displays passed text to every client connected',
usage: ` usage: `
API: { cmd: 'shout', text: '<shout text>' }`, API: { cmd: 'shout', text: '<shout text>' }`,

View File

@ -1,19 +1,34 @@
/* /**
Description: Allows calling client to change their nickname color * @author Marzavec ( https://github.com/marzavec )
*/ * @summary Update name color
* @version 1.0.0
* @description Allows calling client to change their nickname color
* @module changecolor
*/
import { import {
getUserDetails, getUserDetails,
} from '../utility/_UAC'; } from '../utility/_UAC.js';
// module support functions /**
* Validate a string as a valid hex color string
* @param {string} color - Color string to validate
* @private
* @todo Move into utility module
* @return {boolean}
*/
const verifyColor = (color) => /(^[0-9A-F]{6}$)|(^[0-9A-F]{3}$)/i.test(color); const verifyColor = (color) => /(^[0-9A-F]{6}$)|(^[0-9A-F]{3}$)/i.test(color);
// module main /**
* Executes when invoked by a remote client
* @param {Object} env - Enviroment object with references to core, server, socket & payload
* @public
* @return {void}
*/
export async function run({ export async function run({
server, socket, payload, server, socket, payload,
}) { }) {
const channel = socket.channel; const { channel } = socket;
if (server.police.frisk(socket.address, 1)) { if (server.police.frisk(socket.address, 1)) {
return server.reply({ return server.reply({
@ -25,7 +40,7 @@ export async function run({
// verify user data is string // verify user data is string
if (typeof payload.color !== 'string') { if (typeof payload.color !== 'string') {
return true; return false;
} }
// make sure requested nickname meets standards // make sure requested nickname meets standards
@ -60,12 +75,24 @@ export async function run({
return true; return true;
} }
// module hook functions /**
* Automatically executes once after server is ready to register this modules hooks
* @param {Object} server - Reference to server enviroment object
* @public
* @return {void}
*/
export function initHooks(server) { export function initHooks(server) {
server.registerHook('in', 'chat', this.colorCheck.bind(this), 29); server.registerHook('in', 'chat', this.colorCheck.bind(this), 29);
} }
// hooks chat commands checking for /color /**
* Executes every time an incoming chat command is invoked
* @param {Object} env - Enviroment object with references to core, server, socket & payload
* @public
* @return {{Object|boolean|string}} Object = same/altered payload,
* false = suppress action,
* string = error
*/
export function colorCheck({ export function colorCheck({
core, server, socket, payload, core, server, socket, payload,
}) { }) {
@ -103,11 +130,27 @@ export function colorCheck({
return payload; return payload;
} }
// module meta /**
* The following payload properties are required to invoke this module:
* "color"
* @public
* @typedef {Array} changecolor/requiredData
*/
export const requiredData = ['color']; export const requiredData = ['color'];
/**
* Module meta information
* @public
* @typedef {Object} changecolor/info
* @property {string} name - Module command name
* @property {string} category - Module category name
* @property {string} description - Information about module
* @property {string} usage - Information about module usage
*/
export const info = { export const info = {
name: 'changecolor', name: 'changecolor',
description: 'This will change your nickname color', category: 'core',
description: 'Allows calling client to change their nickname color',
usage: ` usage: `
API: { cmd: 'changecolor', color: '<new color as hex>' } API: { cmd: 'changecolor', color: '<new color as hex>' }
Text: /color <new color as hex> Text: /color <new color as hex>

View File

@ -1,19 +1,28 @@
/* eslint eqeqeq: 0 */ /* eslint eqeqeq: 0 */
/* /**
Description: Allows calling client to change their current nickname * @author Marzavec ( https://github.com/marzavec )
*/ * @summary Update nickname
* @version 1.0.0
* @description Allows calling client to change their current nickname
* @module changenick
*/
import { import {
verifyNickname, verifyNickname,
getUserDetails, getUserDetails,
} from '../utility/_UAC'; } from '../utility/_UAC.js';
// module main /**
* Executes when invoked by a remote client
* @param {Object} env - Enviroment object with references to core, server, socket & payload
* @public
* @return {void}
*/
export async function run({ export async function run({
core, server, socket, payload, server, socket, payload,
}) { }) {
const channel = socket.channel; const { channel } = socket;
if (server.police.frisk(socket.address, 6)) { if (server.police.frisk(socket.address, 6)) {
return server.reply({ return server.reply({
@ -40,18 +49,6 @@ export async function run({
}, socket); }, socket);
} }
// prevent admin impersonation
// @todo prevent mod impersonation
if (newNick.toLowerCase() === core.config.adminName.toLowerCase()) {
server.police.frisk(socket.address, 4);
return server.reply({
cmd: 'warn', // @todo Add numeric error code as `id`
text: 'You are not the admin, liar!',
channel, // @todo Multichannel
}, socket);
}
if (newNick == previousNick) { if (newNick == previousNick) {
return server.reply({ return server.reply({
cmd: 'warn', // @todo Add numeric error code as `id` cmd: 'warn', // @todo Add numeric error code as `id`
@ -132,12 +129,24 @@ export async function run({
return true; return true;
} }
// module hook functions /**
* Automatically executes once after server is ready to register this modules hooks
* @param {Object} server - Reference to server enviroment object
* @public
* @return {void}
*/
export function initHooks(server) { export function initHooks(server) {
server.registerHook('in', 'chat', this.nickCheck.bind(this), 29); server.registerHook('in', 'chat', this.nickCheck.bind(this), 29);
} }
// hooks chat commands checking for /nick /**
* Executes every time an incoming chat command is invoked
* @param {Object} env - Enviroment object with references to core, server, socket & payload
* @public
* @return {{Object|boolean|string}} Object = same/altered payload,
* false = suppress action,
* string = error
*/
export function nickCheck({ export function nickCheck({
core, server, socket, payload, core, server, socket, payload,
}) { }) {
@ -149,7 +158,7 @@ export function nickCheck({
const input = payload.text.split(' '); const input = payload.text.split(' ');
// If there is no nickname target parameter // If there is no nickname target parameter
if (input[1] === undefined) { if (!input[1]) {
server.reply({ server.reply({
cmd: 'warn', // @todo Add numeric error code as `id` cmd: 'warn', // @todo Add numeric error code as `id`
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.',
@ -177,10 +186,27 @@ export function nickCheck({
return payload; return payload;
} }
/**
* The following payload properties are required to invoke this module:
* "nick"
* @public
* @typedef {Array} changenick/requiredData
*/
export const requiredData = ['nick']; export const requiredData = ['nick'];
/**
* Module meta information
* @public
* @typedef {Object} changenick/info
* @property {string} name - Module command name
* @property {string} category - Module category name
* @property {string} description - Information about module
* @property {string} usage - Information about module usage
*/
export const info = { export const info = {
name: 'changenick', name: 'changenick',
description: 'This will change your current connections nickname', category: 'core',
description: 'Allows calling client to change their current nickname',
usage: ` usage: `
API: { cmd: 'changenick', nick: '<new nickname>' } API: { cmd: 'changenick', nick: '<new nickname>' }
Text: /nick <new nickname>`, Text: /nick <new nickname>`,

View File

@ -1,13 +1,23 @@
/* /**
Description: Rebroadcasts any `text` to all clients in a `channel` * @author Marzavec ( https://github.com/marzavec )
*/ * @summary Send chat messages
* @version 1.0.0
* @description Broadcasts passed `text` field to the calling users channel
* @module chat
*/
import { import {
isAdmin, isAdmin,
isModerator, isModerator,
} from '../utility/_UAC'; } from '../utility/_UAC.js';
// module support functions /**
* Check and trim string provided by remote client
* @param {string} text - Subject string
* @private
* @todo Move into utility module
* @return {string|boolean}
*/
const parseText = (text) => { const parseText = (text) => {
// verifies user input is text // verifies user input is text
if (typeof text !== 'string') { if (typeof text !== 'string') {
@ -24,7 +34,12 @@ const parseText = (text) => {
return sanitizedText; return sanitizedText;
}; };
// module main /**
* Executes when invoked by a remote client
* @param {Object} env - Enviroment object with references to core, server, socket & payload
* @public
* @return {void}
*/
export async function run({ export async function run({
core, server, socket, payload, core, server, socket, payload,
}) { }) {
@ -80,13 +95,26 @@ export async function run({
return true; return true;
} }
// module hook functions /**
* Automatically executes once after server is ready to register this modules hooks
* @param {Object} server - Reference to server enviroment object
* @public
* @return {void}
*/
export function initHooks(server) { export function initHooks(server) {
server.registerHook('in', 'chat', this.commandCheckIn.bind(this), 20); server.registerHook('in', 'chat', this.commandCheckIn.bind(this), 20);
server.registerHook('in', 'chat', this.finalCmdCheck.bind(this), 254); server.registerHook('in', 'chat', this.finalCmdCheck.bind(this), 254);
} }
// checks for miscellaneous '/' based commands /**
* Executes every time an incoming chat command is invoked;
* checks for miscellaneous '/' based commands
* @param {Object} env - Enviroment object with references to core, server, socket & payload
* @public
* @return {{Object|boolean|string}} Object = same/altered payload,
* false = suppress action,
* string = error
*/
export function commandCheckIn({ server, socket, payload }) { export function commandCheckIn({ server, socket, payload }) {
if (typeof payload.text !== 'string') { if (typeof payload.text !== 'string') {
return false; return false;
@ -105,6 +133,15 @@ export function commandCheckIn({ server, socket, payload }) {
return payload; return payload;
} }
/**
* Executes every time an incoming chat command is invoked;
* assumes a failed chat command invocation and will reject with notice
* @param {Object} env - Enviroment object with references to core, server, socket & payload
* @public
* @return {{Object|boolean|string}} Object = same/altered payload,
* false = suppress action,
* string = error
*/
export function finalCmdCheck({ server, socket, payload }) { export function finalCmdCheck({ server, socket, payload }) {
if (typeof payload.text !== 'string') { if (typeof payload.text !== 'string') {
return false; return false;
@ -129,9 +166,26 @@ export function finalCmdCheck({ server, socket, payload }) {
return false; return false;
} }
/**
* The following payload properties are required to invoke this module:
* "text"
* @public
* @typedef {Array} chat/requiredData
*/
export const requiredData = ['text']; export const requiredData = ['text'];
/**
* Module meta information
* @public
* @typedef {Object} chat/info
* @property {string} name - Module command name
* @property {string} category - Module category name
* @property {string} description - Information about module
* @property {string} usage - Information about module usage
*/
export const info = { export const info = {
name: 'chat', name: 'chat',
category: 'core',
description: 'Broadcasts passed `text` field to the calling users channel', description: 'Broadcasts passed `text` field to the calling users channel',
usage: ` usage: `
API: { cmd: 'chat', text: '<text to send>' } API: { cmd: 'chat', text: '<text to send>' }

View File

@ -1,8 +1,18 @@
/* /**
Description: Broadcasts an emote to the current channel * @author Marzavec ( https://github.com/marzavec )
*/ * @summary Emote / action text
* @version 1.0.0
* @description Broadcasts an emote to the current channel
* @module emote
*/
// module support functions /**
* Check and trim string provided by remote client
* @param {string} text - Subject string
* @private
* @todo Move into utility module
* @return {string|boolean}
*/
const parseText = (text) => { const parseText = (text) => {
// verifies user input is text // verifies user input is text
if (typeof text !== 'string') { if (typeof text !== 'string') {
@ -19,7 +29,12 @@ const parseText = (text) => {
return sanitizedText; return sanitizedText;
}; };
// module main /**
* Executes when invoked by a remote client
* @param {Object} env - Enviroment object with references to core, server, socket & payload
* @public
* @return {void}
*/
export async function run({ server, socket, payload }) { export async function run({ server, socket, payload }) {
// check user input // check user input
let text = parseText(payload.text); let text = parseText(payload.text);
@ -61,12 +76,25 @@ export async function run({ server, socket, payload }) {
return true; return true;
} }
// module hook functions /**
* Automatically executes once after server is ready to register this modules hooks
* @param {Object} server - Reference to server enviroment object
* @public
* @return {void}
*/
export function initHooks(server) { export function initHooks(server) {
server.registerHook('in', 'chat', this.emoteCheck.bind(this), 30); server.registerHook('in', 'chat', this.emoteCheck.bind(this), 30);
} }
// hooks chat commands checking for /me /**
* Executes every time an incoming chat command is invoked;
* hooks chat commands checking for /me
* @param {Object} env - Enviroment object with references to core, server, socket & payload
* @public
* @return {{Object|boolean|string}} Object = same/altered payload,
* false = suppress action,
* string = error
*/
export function emoteCheck({ export function emoteCheck({
core, server, socket, payload, core, server, socket, payload,
}) { }) {
@ -107,10 +135,27 @@ export function emoteCheck({
return payload; return payload;
} }
/**
* The following payload properties are required to invoke this module:
* "text"
* @public
* @typedef {Array} emote/requiredData
*/
export const requiredData = ['text']; export const requiredData = ['text'];
/**
* Module meta information
* @public
* @typedef {Object} emote/info
* @property {string} name - Module command name
* @property {string} category - Module category name
* @property {string} description - Information about module
* @property {string} usage - Information about module usage
*/
export const info = { export const info = {
name: 'emote', name: 'emote',
description: 'Typical emote / action text', category: 'core',
description: 'Broadcasts an emote to the current channel',
usage: ` usage: `
API: { cmd: 'emote', text: '<emote/action text>' } API: { cmd: 'emote', text: '<emote/action text>' }
Text: /me <emote/action text>`, Text: /me <emote/action text>`,

View File

@ -1,8 +1,17 @@
/* /**
Description: Outputs the current command module list or command categories * @author Marzavec ( https://github.com/marzavec )
*/ * @summary Get help
* @version 1.0.0
* @description Outputs information about the servers current protocol
* @module help
*/
// module main /**
* Executes when invoked by a remote client
* @param {Object} env - Enviroment object with references to core, server, socket & payload
* @public
* @return {void}
*/
export async function run({ export async function run({
core, server, socket, payload, core, server, socket, payload,
}) { }) {
@ -61,12 +70,25 @@ export async function run({
return true; return true;
} }
// module hook functions /**
* Automatically executes once after server is ready to register this modules hooks
* @param {Object} server - Reference to server enviroment object
* @public
* @return {void}
*/
export function initHooks(server) { export function initHooks(server) {
server.registerHook('in', 'chat', this.helpCheck.bind(this), 28); server.registerHook('in', 'chat', this.helpCheck.bind(this), 28);
} }
// hooks chat commands checking for /whisper /**
* Executes every time an incoming chat command is invoked;
* hooks chat commands checking for /help
* @param {Object} env - Enviroment object with references to core, server, socket & payload
* @public
* @return {{Object|boolean|string}} Object = same/altered payload,
* false = suppress action,
* string = error
*/
export function helpCheck({ export function helpCheck({
core, server, socket, payload, core, server, socket, payload,
}) { }) {
@ -93,8 +115,18 @@ export function helpCheck({
return payload; return payload;
} }
/**
* Module meta information
* @public
* @typedef {Object} help/info
* @property {string} name - Module command name
* @property {string} category - Module category name
* @property {string} description - Information about module
* @property {string} usage - Information about module usage
*/
export const info = { export const info = {
name: 'help', name: 'help',
category: 'core',
description: 'Outputs information about the servers current protocol', description: 'Outputs information about the servers current protocol',
usage: ` usage: `
API: { cmd: 'help', command: '<optional command name>' } API: { cmd: 'help', command: '<optional command name>' }

View File

@ -1,22 +1,26 @@
/* /**
Description: Generates a semi-unique channel name then broadcasts it to each client * @author Marzavec ( https://github.com/marzavec )
*/ * @summary Send an invite
* @version 1.0.0
* @description Sends an invite to the target client with the provided channel, or a random channel
* @module invite
*/
import { import {
findUser, findUser,
} from '../utility/_Channels'; } from '../utility/_Channels.js';
import { import {
Errors, Errors,
} from '../utility/_Constants'; } from '../utility/_Constants.js';
import { import {
legacyInviteOut, legacyInviteOut,
legacyInviteReply, legacyInviteReply,
} from '../utility/_LegacyFunctions'; } from '../utility/_LegacyFunctions.js';
// module support functions
/** /**
* Returns the channel that should be invited to. * Returns the channel that should be invited to.
* @param {any} channel * @param {any} channel
* @private
* @return {string} * @return {string}
*/ */
export function getChannel(channel = undefined) { export function getChannel(channel = undefined) {
@ -26,7 +30,12 @@ export function getChannel(channel = undefined) {
return Math.random().toString(36).substr(2, 8); return Math.random().toString(36).substr(2, 8);
} }
// module main /**
* Executes when invoked by a remote client
* @param {Object} env - Enviroment object with references to core, server, socket & payload
* @public
* @return {void}
*/
export async function run({ export async function run({
core, server, socket, payload, core, server, socket, payload,
}) { }) {
@ -96,9 +105,18 @@ export async function run({
return true; return true;
} }
export const requiredData = []; // ['nick']; /**
* Module meta information
* @public
* @typedef {Object} invite/info
* @property {string} name - Module command name
* @property {string} category - Module category name
* @property {string} description - Information about module
* @property {string} usage - Information about module usage
*/
export const info = { export const info = {
name: 'invite', name: 'invite',
category: 'core',
description: 'Sends an invite to the target client with the provided channel, or a random channel.', description: 'Sends an invite to the target client with the provided channel, or a random channel.',
usage: ` usage: `
API: { cmd: 'invite', nick: '<target nickname>', to: '<optional destination channel>' }`, API: { cmd: 'invite', nick: '<target nickname>', to: '<optional destination channel>' }`,

View File

@ -1,29 +1,44 @@
/* eslint no-param-reassign: 0 */ /* eslint no-param-reassign: 0 */
/* eslint import/no-cycle: [0, { ignoreExternal: true }] */
/* /**
Description: Adds requested channel into the calling clients "subscribed channels" * @author Marzavec ( https://github.com/marzavec )
*/ * @summary Join target channel
* @version 1.0.0
* @description Join the target channel using the supplied nick and password
* @module join
*/
import {
getSession,
} from './session.js';
import { import {
canJoinChannel, canJoinChannel,
} from '../utility/_Channels'; socketInChannel,
} from '../utility/_Channels.js';
import { import {
Errors, Errors,
} from '../utility/_Constants'; } from '../utility/_Constants.js';
import { import {
upgradeLegacyJoin, upgradeLegacyJoin,
legacyLevelToLabel, legacyLevelToLabel,
} from '../utility/_LegacyFunctions'; } from '../utility/_LegacyFunctions.js';
import { import {
verifyNickname, verifyNickname,
getUserPerms, getUserPerms,
getUserDetails, getUserDetails,
} from '../utility/_UAC'; } from '../utility/_UAC.js';
// module main /**
* Executes when invoked by a remote client
* @param {Object} env - Enviroment object with references to core, server, socket & payload
* @public
* @return {void}
*/
export async function run({ export async function run({
core, server, socket, payload, core, server, socket, payload,
}) { // check for spam }) {
// check for spam
if (server.police.frisk(socket.address, 3)) { if (server.police.frisk(socket.address, 3)) {
return server.reply({ return server.reply({
cmd: 'warn', cmd: 'warn',
@ -75,7 +90,7 @@ export async function run({
} }
// get trip and level // get trip and level
const { trip, level } = getUserPerms(pass, core.config, channel); const { trip, level } = getUserPerms(pass, core.saltKey, core.appConfig.data, channel);
// store the user values // store the user values
const userInfo = { const userInfo = {
@ -90,13 +105,6 @@ export async function run({
channel, channel,
}; };
// prevent admin impersonation
if (nick.toLowerCase() === core.config.adminName.toLowerCase()) {
if (userInfo.trip !== 'Admin') {
userInfo.nick = `Fake${userInfo.nick}`;
}
}
// check if the nickname already exists in the channel // check if the nickname already exists in the channel
const userExists = server.findSockets({ const userExists = server.findSockets({
channel, channel,
@ -141,6 +149,7 @@ export async function run({
socket.channel = channel; /* @legacy */ socket.channel = channel; /* @legacy */
// @todo multi-channel patch // @todo multi-channel patch
// socket.channels.push(channel); // socket.channels.push(channel);
socket.channels = [channel];
nicks.push(userInfo.nick); /* @legacy */ nicks.push(userInfo.nick); /* @legacy */
users.push({ ...{ isme: true, isBot: socket.isBot }, ...userInfo }); users.push({ ...{ isme: true, isBot: socket.isBot }, ...userInfo });
@ -153,15 +162,110 @@ export async function run({
channel, // @todo Multichannel (?) channel, // @todo Multichannel (?)
}, socket); }, socket);
// update client with new session info
server.reply({
cmd: 'session',
restored: false,
token: getSession(socket, core),
channels: socket.channels,
}, socket);
// stats are fun // stats are fun
core.stats.increment('users-joined'); core.stats.increment('users-joined');
return true; return true;
} }
export const requiredData = []; // ['channel', 'nick']; export function restoreJoin({
server, socket, channel,
}) {
// check if a client is able to join target channel
const mayJoin = canJoinChannel(channel, socket);
if (mayJoin !== true) {
return server.reply({
cmd: 'warn',
text: 'You may not join that channel.',
id: mayJoin,
channel: false, // @todo Multichannel, false for global event
}, socket);
}
// store the user values
const userInfo = {
nick: socket.nick,
trip: socket.trip,
uType: legacyLevelToLabel(socket.level),
hash: socket.hash,
level: socket.level,
userid: socket.userid,
isBot: socket.isBot,
color: socket.color,
channel,
};
// prepare to notify channel peers
const newPeerList = server.findSockets({ channel });
const nicks = []; /* @legacy */
const users = [];
const joinAnnouncement = { ...{ cmd: 'onlineAdd' }, ...userInfo };
// build update notice with new privileges
const updateAnnouncement = {
...getUserDetails(socket),
...{
cmd: 'updateUser',
online: true,
},
};
const isDuplicate = socketInChannel(server, channel, socket);
// send join announcement and prep online set reply
for (let i = 0, l = newPeerList.length; i < l; i += 1) {
if (isDuplicate) {
server.reply(updateAnnouncement, newPeerList[i]);
} else {
server.reply(joinAnnouncement, newPeerList[i]);
}
nicks.push(newPeerList[i].nick); /* @legacy */
users.push({
...{
channel,
isme: false,
},
...getUserDetails(newPeerList[i]),
});
}
nicks.push(userInfo.nick); /* @legacy */
users.push({ ...{ isme: true, isBot: socket.isBot }, ...userInfo });
// reply with channel peer list
server.reply({
cmd: 'onlineSet',
nicks, /* @legacy */
users,
channel, // @todo Multichannel (?)
}, socket);
socket.channel = channel; /* @legacy */
socket.channels.push(channel);
return true;
}
/**
* Module meta information
* @public
* @typedef {Object} join/info
* @property {string} name - Module command name
* @property {string} category - Module category name
* @property {string} description - Information about module
* @property {string} usage - Information about module usage
*/
export const info = { export const info = {
name: 'join', name: 'join',
category: 'core',
description: 'Join the target channel using the supplied nick and password', description: 'Join the target channel using the supplied nick and password',
usage: ` usage: `
API: { cmd: 'join', nick: '<your nickname>', pass: '<optional password>', channel: '<target channel>' }`, API: { cmd: 'join', nick: '<your nickname>', pass: '<optional password>', channel: '<target channel>' }`,

View File

@ -1,10 +1,17 @@
/* /**
Description: Outputs more info than the legacy stats command * @author Marzavec ( https://github.com/marzavec )
*/ * @summary Get stats
* @version 1.0.0
// module support functions * @description Sends back current server stats to the calling client
const { stripIndents } = require('common-tags'); * @module morestats
*/
/**
* Format input time into string
* @param {Date} time - Subject date
* @private
* @return {string}
*/
const formatTime = (time) => { const formatTime = (time) => {
let seconds = time[0] + time[1] / 1e9; let seconds = time[0] + time[1] / 1e9;
@ -20,50 +27,101 @@ const formatTime = (time) => {
return `${days.toFixed(0)}d ${hours.toFixed(0)}h ${minutes.toFixed(0)}m ${seconds.toFixed(0)}s`; return `${days.toFixed(0)}d ${hours.toFixed(0)}h ${minutes.toFixed(0)}m ${seconds.toFixed(0)}s`;
}; };
// module main /**
* Executes when invoked by a remote client
* @param {Object} env - Enviroment object with references to core, server, socket & payload
* @public
* @return {void}
*/
export async function run({ core, server, socket }) { export async function run({ core, server, socket }) {
// gather connection and channel count // gather connection and channel count
let ips = {}; const ips = {};
let channels = {}; const channels = {};
// for (const client of server.clients) { // @todo use public channels from core.appConfig.data
const publicChanCounts = {
lounge: 0,
meta: 0,
math: 0,
physics: 0,
chemistry: 0,
technology: 0,
programming: 0,
games: 0,
banana: 0,
chinese: 0,
};
// @todo code resuage between here and `session`; should share exported function
server.clients.forEach((client) => { server.clients.forEach((client) => {
if (client.channel) { if (client.channel) {
channels[client.channel] = true; channels[client.channel] = true;
ips[client.address] = true; ips[client.address] = true;
if (typeof publicChanCounts[client.channel] !== 'undefined') {
publicChanCounts[client.channel] += 1;
}
} }
}); });
const uniqueClientCount = Object.keys(ips).length; const uniqueClientCount = Object.keys(ips).length;
const uniqueChannels = Object.keys(channels).length; const uniqueChannels = Object.keys(channels).length;
const joins = core.stats.get('users-joined') || 0;
ips = null; const invites = core.stats.get('invites-sent') || 0;
channels = null; const messages = core.stats.get('messages-sent') || 0;
const banned = core.stats.get('users-banned') || 0;
const kicked = core.stats.get('users-kicked') || 0;
const stats = core.stats.get('stats-requested') || 0;
const uptime = formatTime(process.hrtime(core.stats.get('start-time')));
// dispatch info // dispatch info
server.reply({ server.reply({
cmd: 'info', cmd: 'info',
text: stripIndents`current-connections: ${uniqueClientCount} users: uniqueClientCount,
current-channels: ${uniqueChannels} chans: uniqueChannels,
users-joined: ${(core.stats.get('users-joined') || 0)} joins,
invites-sent: ${(core.stats.get('invites-sent') || 0)} invites,
messages-sent: ${(core.stats.get('messages-sent') || 0)} messages,
users-banned: ${(core.stats.get('users-banned') || 0)} banned,
users-kicked: ${(core.stats.get('users-kicked') || 0)} kicked,
stats-requested: ${(core.stats.get('stats-requested') || 0)} stats,
server-uptime: ${formatTime(process.hrtime(core.stats.get('start-time')))}`, uptime,
public: publicChanCounts,
text: `current-connections: ${uniqueClientCount}
current-channels: ${uniqueChannels}
users-joined: ${joins}
invites-sent: ${invites}
messages-sent: ${messages}
users-banned: ${banned}
users-kicked: ${kicked}
stats-requested: ${stats}
server-uptime: ${uptime}`,
channel: socket.channel, // @todo Multichannel channel: socket.channel, // @todo Multichannel
}, socket); }, socket);
// stats are fun // stats are fun
core.stats.increment('stats-requested'); core.stats.increment('stats-requested');
return true;
} }
// module hook functions /**
* Automatically executes once after server is ready to register this modules hooks
* @param {Object} server - Reference to server enviroment object
* @public
* @return {void}
*/
export function initHooks(server) { export function initHooks(server) {
server.registerHook('in', 'chat', this.statsCheck.bind(this), 26); server.registerHook('in', 'chat', this.statsCheck.bind(this), 26);
} }
// hooks chat commands checking for /stats /**
* Executes every time an incoming chat command is invoked;
* hooks chat commands checking for /stats
* @param {Object} env - Enviroment object with references to core, server, socket & payload
* @public
* @return {{Object|boolean|string}} Object = same/altered payload,
* false = suppress action,
* string = error
*/
export function statsCheck({ export function statsCheck({
core, server, socket, payload, core, server, socket, payload,
}) { }) {
@ -87,8 +145,18 @@ export function statsCheck({
return payload; return payload;
} }
/**
* Module meta information
* @public
* @typedef {Object} morestats/info
* @property {string} name - Module command name
* @property {string} category - Module category name
* @property {string} description - Information about module
* @property {string} usage - Information about module usage
*/
export const info = { export const info = {
name: 'morestats', name: 'morestats',
category: 'core',
description: 'Sends back current server stats to the calling client', description: 'Sends back current server stats to the calling client',
usage: ` usage: `
API: { cmd: 'morestats' } API: { cmd: 'morestats' }

View File

@ -1,171 +0,0 @@
/*
Description: Changes the current channel of the calling socket
@deprecated This module will be removed or replaced
*/
import {
getUserDetails,
} from '../utility/_UAC';
// module main
export async function run({ server, socket, payload }) {
// check for spam
if (server.police.frisk(socket.address, 6)) {
return server.reply({
cmd: 'warn', // @todo Add numeric error code as `id`
text: 'You are changing channels too fast. Wait a moment before trying again.',
channel: socket.channel, // @todo Multichannel
}, socket);
}
// check user input
if (typeof payload.channel !== 'string') {
return true;
}
if (payload.channel === '') {
return server.reply({
cmd: 'warn', // @todo Add numeric error code as `id`
text: 'Cannot move to an empty channel.',
channel: socket.channel, // @todo Multichannel
}, socket);
}
if (payload.channel === socket.channel) { // @todo Multichannel update
// they are trying to rejoin the channel
return true;
}
// check that the nickname isn't already in target channel
const currentNick = socket.nick.toLowerCase();
const userExists = server.findSockets({
channel: payload.channel,
nick: (targetNick) => targetNick.toLowerCase() === currentNick,
});
if (userExists.length > 0) {
// That nickname is already in that channel
return true;
}
// broadcast leave notice to peers
const peerList = server.findSockets({ channel: socket.channel });
if (peerList.length > 1) {
for (let i = 0, l = peerList.length; i < l; i += 1) {
server.reply({
cmd: 'onlineRemove',
nick: peerList[i].nick,
userid: peerList[i].userid,
channel: socket.channel, // @todo Multichannel
}, socket);
if (socket.userid !== peerList[i].userid) {
server.reply({
cmd: 'onlineRemove',
nick: socket.nick,
userid: socket.userid,
channel: socket.channel, // @todo Multichannel
}, peerList[i]);
}
}
}
// broadcast join notice to new peers
const newPeerList = server.findSockets({ channel: payload.channel });
const moveAnnouncement = {
...{
cmd: 'onlineAdd',
channel: payload.channel, // @todo Multichannel
},
...getUserDetails(socket),
};
const nicks = [];
const users = [];
for (let i = 0, l = newPeerList.length; i < l; i += 1) {
server.reply(moveAnnouncement, newPeerList[i]);
nicks.push(newPeerList[i].nick); /* @legacy */
users.push({
...{
channel: payload.channel,
isme: false,
},
...getUserDetails(newPeerList[i]),
});
}
nicks.push(socket.nick); /* @legacy */
users.push({
...{
channel: payload.channel,
isme: true,
},
...getUserDetails(socket),
});
// reply with new user list
server.reply({
cmd: 'onlineSet',
nicks,
users,
channel: socket.channel, // @todo Multichannel (!)
}, socket);
// commit change
socket.channel = payload.channel; // eslint-disable-line no-param-reassign
return true;
}
// module hook functions
export function initHooks(server) {
server.registerHook('in', 'chat', this.moveCheck.bind(this), 29);
}
export function moveCheck({
core, server, socket, payload,
}) {
if (typeof payload.text !== 'string') {
return false;
}
if (payload.text.startsWith('/move ')) {
const input = payload.text.split(' ');
// If there is no channel target parameter
if (input[1] === undefined) {
server.reply({
cmd: 'warn', // @todo Add numeric error code as `id`
text: 'Refer to `/help move` for instructions on how to use this command.',
channel: socket.channel, // @todo Multichannel
}, socket);
return false;
}
this.run({
core,
server,
socket,
payload: {
cmd: 'move',
channel: input[1],
},
});
return false;
}
return payload;
}
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>' }
Text: /move <new channel>`,
};

View File

@ -1,12 +1,32 @@
/* eslint no-empty-function: 0 */ /* eslint no-empty-function: 0 */
/*
Description: This module is only in place to supress error notices legacy sources may get
*/
// module main /**
* @author Marzavec ( https://github.com/marzavec )
* @summary Legacy support module
* @version 1.0.0
* @description This module is only in place to supress error notices legacy clients may get
* @module ping
*/
/**
* Executes when invoked by a remote client
* @public
* @return {void}
*/
export async function run() { } export async function run() { }
/**
* Module meta information
* @public
* @typedef {Object} ping/info
* @property {string} name - Module command name
* @property {string} category - Module category name
* @property {string} description - Information about module
* @property {string} usage - Information about module usage
*/
export const info = { export const info = {
name: 'ping', name: 'ping',
description: 'This module is only in place to supress error notices legacy sources may get', category: 'core',
description: 'This module is only in place to supress error notices legacy clients may get',
usage: 'none',
}; };

View File

@ -1,76 +1,193 @@
/* eslint no-param-reassign: 0 */ /* eslint import/no-cycle: [0, { ignoreExternal: true }] */
/* /**
Description: Create a new socket session or restore previous session * @author Marzavec ( https://github.com/marzavec )
*/ * @summary Restore session
* @version 1.0.0
* @description Restore previous state by session
* @module session
*/
// module support functions import fs from 'fs';
const createSessionID = () => { import jsonwebtoken from 'jsonwebtoken';
let sessionID = '';
for (let i = 0, j = 32; i < j; i += 1) {
sessionID += Math.random().toString(36).substr(2, 9);
}
return sessionID;
};
// module main import {
export async function run({ server, socket, payload }) { verifyNickname,
// gather connection and channel count } from '../utility/_UAC.js';
let ips = {}; import {
let channels = {}; Errors,
// @todo use public channel flag } from '../utility/_Constants.js';
const publicChanCounts = { import {
lounge: 0, restoreJoin,
meta: 0, } from './join.js';
math: 0,
physics: 0,
chemistry: 0,
technology: 0,
programming: 0,
games: 0,
banana: 0,
chinese: 0,
};
// todo code resuage between here and `morestats`, export function const SessionLocation = './session.key';
server.clients.forEach((client) => {
if (client.channel) { /**
channels[client.channel] = true; * Get a fresh session string for target socket
ips[client.address] = true; * @param {Object} socket
if (typeof publicChanCounts[client.channel] !== 'undefined') { * @param {Object} core
publicChanCounts[client.channel] += 1; * @returns {object}
} */
} export function getSession(socket, core) {
return jsonwebtoken.sign({
channel: socket.channel,
channels: socket.channels,
color: socket.color,
isBot: socket.isBot,
level: socket.level,
nick: socket.nick,
trip: socket.trip,
userid: socket.userid,
uType: socket.uType, /* @legacy */
muzzled: socket.muzzled || false,
banned: socket.banned || false,
}, core.sessionKey, {
expiresIn: '7 days',
}); });
const uniqueClientCount = Object.keys(ips).length;
const uniqueChannels = Object.keys(channels).length;
ips = null;
channels = null;
// @todo restore session
socket.sessionID = createSessionID();
socket.hcProtocol = 2;
socket.userid = Math.floor(Math.random() * 9999999999999);
socket.hash = server.getSocketHash(socket);
socket.isBot = payload.isBot || false;
socket.color = false;
// dispatch info
server.reply({
cmd: 'session',
users: uniqueClientCount,
chans: uniqueChannels,
public: publicChanCounts,
sessionID: socket.sessionID,
restored: false,
}, socket);
} }
/**
* Reply to target socket with session failure notice
* @param {Object} server
* @param {Object} socket
* @returns {boolean}
*/
function notifyFailure(server, socket) {
server.reply({
cmd: 'error',
id: Errors.Session.BAD_SESSION,
text: 'Invalid session',
}, socket);
return false;
}
/**
* Executes when invoked by a remote client
* @param {Object} env - Enviroment object with references to core, server, socket & payload
* @public
* @return {void}
*/
export async function run({
core, server, socket, payload,
}) {
if (typeof payload.token === 'undefined') {
return notifyFailure(server, socket);
}
let session = false;
try {
session = jsonwebtoken.verify(payload.token, core.sessionKey);
} catch (err) {
return notifyFailure(server, socket);
}
// validate session
if (typeof session.channel !== 'string') {
return notifyFailure(server, socket);
}
if (Array.isArray(session.channels) === false) {
return notifyFailure(server, socket);
}
if (typeof session.color !== 'string' && typeof session.color !== 'boolean') {
return notifyFailure(server, socket);
}
if (typeof session.isBot !== 'boolean') {
return notifyFailure(server, socket);
}
if (typeof session.level !== 'number') {
return notifyFailure(server, socket);
}
if (verifyNickname(session.nick) === false) {
return notifyFailure(server, socket);
}
if (typeof session.trip !== 'string') {
return notifyFailure(server, socket);
}
if (typeof session.userid !== 'number') {
return notifyFailure(server, socket);
}
if (typeof session.uType !== 'string') {
return notifyFailure(server, socket);
}
if (typeof session.muzzled !== 'boolean') {
return notifyFailure(server, socket);
}
if (typeof session.banned !== 'boolean') {
return notifyFailure(server, socket);
}
// populate socket info with validated session
socket.channels = [];
socket.color = session.color;
socket.isBot = session.isBot;
socket.level = session.level;
socket.nick = session.nick;
socket.trip = session.trip;
socket.userid = session.userid;
socket.uType = session.uType; /* @legacy */
socket.muzzled = session.muzzled;
socket.banned = session.banned;
socket.hash = server.getSocketHash(socket);
socket.hcProtocol = 2;
for (let i = 0, j = session.channels.length; i < j; i += 1) {
restoreJoin({
core,
server,
socket,
channel: session.channels[i],
}, true);
}
// dispatch updated session
server.reply({
cmd: 'session',
restored: true,
token: getSession(socket, core),
channels: socket.channels,
}, socket);
return true;
}
/**
* Automatically executes once after server is ready
* @param {Object} core - Reference to core enviroment object
* @public
* @return {void}
*/
export function init(core) {
// load the encryption key if required
if (typeof core.sessionKey === 'undefined') {
core.sessionKey = fs.readFileSync(SessionLocation);
}
}
/**
* Module meta information
* @public
* @typedef {Object} session/info
* @property {string} name - Module command name
* @property {string} category - Module category name
* @property {string} description - Information about module
* @property {string} usage - Information about module usage
*/
export const info = { export const info = {
name: 'session', name: 'session',
description: 'Restore previous state by session id or return new session id (currently unavailable)', category: 'core',
usage: ` description: 'Restore previous state by session or create new session',
API: { cmd: 'session', id: '<previous session>' }`, usage: "API: { cmd: 'session', id: '<previous session>' }",
}; };

View File

@ -1,8 +1,17 @@
/* /**
Description: Legacy stats output, kept for compatibility, outputs user and channel count * @author Marzavec ( https://github.com/marzavec )
*/ * @summary Simple stats
* @version 1.0.0
* @description Sends back legacy server stats to the calling client
* @module stats
*/
// module main /**
* Executes when invoked by a remote client
* @param {Object} env - Enviroment object with references to core, server, socket & payload
* @public
* @return {void}
*/
export async function run({ core, server, socket }) { export async function run({ core, server, socket }) {
// gather connection and channel count // gather connection and channel count
let ips = {}; let ips = {};
@ -32,8 +41,18 @@ export async function run({ core, server, socket }) {
core.stats.increment('stats-requested'); core.stats.increment('stats-requested');
} }
/**
* Module meta information
* @public
* @typedef {Object} stats/info
* @property {string} name - Module command name
* @property {string} category - Module category name
* @property {string} description - Information about module
* @property {string} usage - Information about module usage
*/
export const info = { export const info = {
name: 'stats', name: 'stats',
category: 'core',
description: 'Sends back legacy server stats to the calling client', description: 'Sends back legacy server stats to the calling client',
usage: ` usage: `
API: { cmd: 'stats' }`, API: { cmd: 'stats' }`,

View File

@ -1,21 +1,31 @@
/* /**
Description: Display text on targets screen that only they can see * @author Marzavec ( https://github.com/marzavec )
@todo This should be changed to it's own event type, instead of `info` * @summary Send whisper
* @version 1.0.0
* @description Display text on target users screen that only they can see
* @module whisper
* @todo This should be changed to it's own event type, instead of `info`
and accept a `userid` rather than `nick` and accept a `userid` rather than `nick`
*/ */
import { import {
findUser, findUser,
} from '../utility/_Channels'; } from '../utility/_Channels.js';
import { import {
Errors, Errors,
} from '../utility/_Constants'; } from '../utility/_Constants.js';
import { import {
legacyWhisperOut, legacyWhisperOut,
legacyWhisperReply, legacyWhisperReply,
} from '../utility/_LegacyFunctions'; } from '../utility/_LegacyFunctions.js';
// module support functions /**
* Check and trim string provided by remote client
* @param {string} text - Subject string
* @private
* @todo Move into utility module
* @return {string|boolean}
*/
const parseText = (text) => { const parseText = (text) => {
// verifies user input is text // verifies user input is text
if (typeof text !== 'string') { if (typeof text !== 'string') {
@ -32,7 +42,12 @@ const parseText = (text) => {
return sanitizedText; return sanitizedText;
}; };
// module main /**
* Executes when invoked by a remote client
* @param {Object} env - Enviroment object with references to core, server, socket & payload
* @public
* @return {void}
*/
export async function run({ server, socket, payload }) { export async function run({ server, socket, payload }) {
// if this is a legacy client add missing params to payload // if this is a legacy client add missing params to payload
if (socket.hcProtocol === 1) { if (socket.hcProtocol === 1) {
@ -94,12 +109,25 @@ export async function run({ server, socket, payload }) {
return true; return true;
} }
// module hook functions /**
* Automatically executes once after server is ready to register this modules hooks
* @param {Object} server - Reference to server enviroment object
* @public
* @return {void}
*/
export function initHooks(server) { export function initHooks(server) {
server.registerHook('in', 'chat', this.whisperCheck.bind(this), 20); server.registerHook('in', 'chat', this.whisperCheck.bind(this), 20);
} }
// hooks chat commands checking for /whisper /**
* Executes every time an incoming chat command is invoked;
* hooks chat commands checking for /whisper
* @param {Object} env - Enviroment object with references to core, server, socket & payload
* @public
* @return {{Object|boolean|string}} Object = same/altered payload,
* false = suppress action,
* string = error
*/
export function whisperCheck({ export function whisperCheck({
core, server, socket, payload, core, server, socket, payload,
}) { }) {
@ -111,7 +139,7 @@ export function whisperCheck({
const input = payload.text.split(' '); const input = payload.text.split(' ');
// If there is no nickname target parameter // If there is no nickname target parameter
if (input[1] === undefined) { if (!input[1]) {
server.reply({ server.reply({
cmd: 'warn', // @todo Add numeric error code as `id` cmd: 'warn', // @todo Add numeric error code as `id`
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.',
@ -173,10 +201,27 @@ export function whisperCheck({
return payload; return payload;
} }
/**
* The following payload properties are required to invoke this module:
* "nick", "text"
* @public
* @typedef {Array} whisper/requiredData
*/
export const requiredData = ['nick', 'text']; export const requiredData = ['nick', 'text'];
/**
* Module meta information
* @public
* @typedef {Object} whisper/info
* @property {string} name - Module command name
* @property {string} category - Module category name
* @property {string} description - Information about module
* @property {string} usage - Information about module usage
*/
export const info = { export const info = {
name: 'whisper', name: 'whisper',
description: 'Display text on targets screen that only they can see', category: 'core',
description: 'Display text on target users screen that only they can see',
usage: ` usage: `
API: { cmd: 'whisper', nick: '<target name>', text: '<text to whisper>' } API: { cmd: 'whisper', nick: '<target name>', text: '<text to whisper>' }
Text: /whisper <target name> <text to whisper> Text: /whisper <target name> <text to whisper>

View File

@ -1,9 +1,21 @@
/* /**
Description: This module will be directly called by the server event handler * @author Marzavec ( https://github.com/marzavec )
when a socket connection is closed or lost. * @summary Disconnection handler
*/ * @version 1.0.0
* @description The server invokes this module each time a websocket connection is disconnected
* @module disconnect
*/
// module main import {
socketInChannel,
} from '../utility/_Channels.js';
/**
* Executes when invoked by a remote client
* @param {Object} env - Enviroment object with references to core, server, socket & payload
* @public
* @return {void}
*/
export async function run({ server, socket, payload }) { export async function run({ server, socket, payload }) {
if (payload.cmdKey !== server.cmdKey) { if (payload.cmdKey !== server.cmdKey) {
// internal command attempt by client, increase rate limit chance and ignore // internal command attempt by client, increase rate limit chance and ignore
@ -11,14 +23,17 @@ export async function run({ server, socket, payload }) {
} }
// send leave notice to client peers // send leave notice to client peers
// @todo Multichannel update
if (socket.channel) { if (socket.channel) {
const isDuplicate = socketInChannel(server, socket.channel, socket);
if (isDuplicate === false) {
server.broadcast({ server.broadcast({
cmd: 'onlineRemove', cmd: 'onlineRemove',
userid: socket.userid, nick: socket.nick,
nick: socket.nick, /* @legacy */
channel: socket.channel, // @todo Multichannel
}, { channel: socket.channel }); }, { channel: socket.channel });
} }
}
// commit close just in case // commit close just in case
socket.terminate(); socket.terminate();
@ -26,9 +41,26 @@ export async function run({ server, socket, payload }) {
return true; return true;
} }
/**
* The following payload properties are required to invoke this module:
* "cmdKey"
* @public
* @typedef {Array} disconnect/requiredData
*/
export const requiredData = ['cmdKey']; export const requiredData = ['cmdKey'];
/**
* Module meta information
* @public
* @typedef {Object} disconnect/info
* @property {string} name - Module command name
* @property {string} category - Module category name
* @property {string} description - Information about module
* @property {string} usage - Information about module usage
*/
export const info = { export const info = {
name: 'disconnect', name: 'disconnect',
category: 'internal',
description: 'Internally used to relay disconnect events to clients',
usage: 'Internal Use Only', usage: 'Internal Use Only',
description: 'Internally used to relay `onlineRemove` event to clients',
}; };

View File

@ -1,8 +1,18 @@
/* /**
Description: Used to relay warnings to clients internally * @author Marzavec ( https://github.com/marzavec )
*/ * @summary Bridge warning events to a user
* @version 1.0.0
* @description If a warning occurs within the server, this module will relay the warning to the
* client
* @module socketreply
*/
// module main /**
* Executes when invoked by a remote client
* @param {Object} env - Enviroment object with references to core, server, socket & payload
* @public
* @return {void}
*/
export async function run({ server, socket, payload }) { export async function run({ server, socket, payload }) {
if (payload.cmdKey !== server.cmdKey) { if (payload.cmdKey !== server.cmdKey) {
// internal command attempt by client, increase rate limit chance and ignore // internal command attempt by client, increase rate limit chance and ignore
@ -10,18 +20,32 @@ export async function run({ server, socket, payload }) {
} }
// send warning to target socket // send warning to target socket
server.reply({ return server.reply({
cmd: 'warn', // @todo Add numeric error code as `id` cmd: 'warn',
text: payload.text, text: payload.text,
channel: socket.channel || false, // @todo Multichannel
}, socket); }, socket);
return true;
} }
/**
* The following payload properties are required to invoke this module:
* "cmdKey", "text"
* @public
* @typedef {Array} socketreply/requiredData
*/
export const requiredData = ['cmdKey', 'text']; export const requiredData = ['cmdKey', 'text'];
/**
* Module meta information
* @public
* @typedef {Object} socketreply/info
* @property {string} name - Module command name
* @property {string} category - Module category name
* @property {string} description - Information about module
* @property {string} usage - Information about module usage
*/
export const info = { export const info = {
name: 'socketreply', name: 'socketreply',
usage: 'Internal Use Only', category: 'internal',
description: 'Internally used to relay warnings to clients', description: 'Internally used to relay warnings to clients',
usage: 'Internal Use Only',
}; };

View File

@ -1,21 +1,29 @@
/* eslint no-console: 0 */ /**
/* * @author Marzavec ( https://github.com/marzavec )
Description: Adds the target socket's ip to the ratelimiter * @summary Ban a user
*/ * @version 1.0.0
* @description Bans target user by name
* @module ban
*/
import { import {
isModerator, isModerator,
getUserDetails, getUserDetails,
levels, levels,
} from '../utility/_UAC'; } from '../utility/_UAC.js';
import { import {
Errors, Errors,
} from '../utility/_Constants'; } from '../utility/_Constants.js';
import { import {
findUser, findUser,
} from '../utility/_Channels'; } from '../utility/_Channels.js';
// module main /**
* Executes when invoked by a remote client
* @param {Object} env - Enviroment object with references to core, server, socket & payload
* @public
* @return {void}
*/
export async function run({ export async function run({
core, server, socket, payload, core, server, socket, payload,
}) { }) {
@ -27,12 +35,12 @@ export async function run({
// check user input // check user input
if (socket.hcProtocol === 1) { if (socket.hcProtocol === 1) {
if (typeof payload.nick !== 'string') { if (typeof payload.nick !== 'string') {
return true; return false;
} }
payload.channel = socket.channel; // eslint-disable-line no-param-reassign payload.channel = socket.channel; // eslint-disable-line no-param-reassign
} else if (typeof payload.userid !== 'number') { } else if (typeof payload.userid !== 'number') {
return true; return false;
} }
// find target user // find target user
@ -89,10 +97,19 @@ export async function run({
return true; return true;
} }
// export const requiredData = ['nick']; /**
* Module meta information
* @public
* @typedef {Object} ban/info
* @property {string} name - Module command name
* @property {string} category - Module category name
* @property {string} description - Information about module
* @property {string} usage - Information about module usage
*/
export const info = { export const info = {
name: 'ban', name: 'ban',
description: 'Disconnects the target nickname in the same channel as calling socket & adds to ratelimiter', category: 'moderators',
description: 'Bans target user by name',
usage: ` usage: `
API: { cmd: 'ban', nick: '<target nickname>' }`, API: { cmd: 'ban', nick: '<target nickname>' }`,
}; };

View File

@ -1,29 +1,32 @@
/* eslint no-param-reassign: 0 */ /* eslint no-param-reassign: 0 */
/* eslint no-multi-assign: 0 */ /* eslint no-multi-assign: 0 */
/* /**
* Description: Make a user (spammer) dumb (mute) * @author OpSimple ( https://github.com/OpSimple )
* Author: simple * @summary Muzzle a user
* @version 1.0.0
* @description Globally shadow mute a connection. Optional allies array will see muted messages.
* @module dumb
*/ */
import { import {
isModerator, isModerator,
} from '../utility/_UAC'; } from '../utility/_UAC.js';
import { import {
findUser, findUser,
} from '../utility/_Channels'; } from '../utility/_Channels.js';
import { import {
Errors, Errors,
} from '../utility/_Constants'; } from '../utility/_Constants.js';
import { import {
legacyInviteReply, legacyInviteReply,
legacyWhisperReply, legacyWhisperReply,
} from '../utility/_LegacyFunctions'; } from '../utility/_LegacyFunctions.js';
// module support functions
/** /**
* Returns the channel that should be invited to. * Returns the channel that should be invited to.
* @param {any} channel * @param {any} channel
* @private
* @return {string} * @return {string}
*/ */
export function getChannel(channel = undefined) { export function getChannel(channel = undefined) {
@ -33,6 +36,13 @@ export function getChannel(channel = undefined) {
return Math.random().toString(36).substr(2, 8); return Math.random().toString(36).substr(2, 8);
} }
/**
* Check and trim string provided by remote client
* @param {string} text - Subject string
* @private
* @todo Move into utility module
* @return {string|boolean}
*/
const parseText = (text) => { const parseText = (text) => {
// verifies user input is text // verifies user input is text
if (typeof text !== 'string') { if (typeof text !== 'string') {
@ -49,14 +59,24 @@ const parseText = (text) => {
return sanitizedText; return sanitizedText;
}; };
// module constructor /**
* Automatically executes once after server is ready
* @param {Object} core - Reference to core enviroment object
* @public
* @return {void}
*/
export function init(core) { export function init(core) {
if (typeof core.muzzledHashes === 'undefined') { if (typeof core.muzzledHashes === 'undefined') {
core.muzzledHashes = {}; core.muzzledHashes = {};
} }
} }
// module main /**
* Executes when invoked by a remote client
* @param {Object} env - Enviroment object with references to core, server, socket & payload
* @public
* @return {void}
*/
export async function run({ export async function run({
core, server, socket, payload, core, server, socket, payload,
}) { }) {
@ -78,6 +98,7 @@ export async function run({
// find target user // find target user
const targetUser = findUser(server, payload); const targetUser = findUser(server, payload);
if (!targetUser) { if (!targetUser) {
return server.reply({ return server.reply({
cmd: 'warn', cmd: 'warn',
@ -117,14 +138,27 @@ export async function run({
return true; return true;
} }
// module hook functions /**
* Automatically executes once after server is ready to register this modules hooks
* @param {Object} server - Reference to server enviroment object
* @public
* @return {void}
*/
export function initHooks(server) { export function initHooks(server) {
server.registerHook('in', 'chat', this.chatCheck.bind(this), 10); server.registerHook('in', 'chat', this.chatCheck.bind(this), 10);
server.registerHook('in', 'invite', this.inviteCheck.bind(this), 10); server.registerHook('in', 'invite', this.inviteCheck.bind(this), 10);
server.registerHook('in', 'whisper', this.whisperCheck.bind(this), 10); server.registerHook('in', 'whisper', this.whisperCheck.bind(this), 10);
} }
// hook incoming chat commands, shadow-prevent chat if they are muzzled /**
* Executes every time an incoming chat command is invoked;
* hook incoming chat commands, shadow-prevent chat if they are muzzled
* @param {Object} env - Enviroment object with references to core, server, socket & payload
* @public
* @return {{Object|boolean|string}} Object = same/altered payload,
* false = suppress action,
* string = error
*/
export function chatCheck({ export function chatCheck({
core, server, socket, payload, core, server, socket, payload,
}) { }) {
@ -179,7 +213,15 @@ export function chatCheck({
return payload; return payload;
} }
// shadow-prevent all invites from muzzled users /**
* Executes every time an incoming chat command is invoked;
* shadow-prevent all invites from muzzled users
* @param {Object} env - Enviroment object with references to core, server, socket & payload
* @public
* @return {{Object|boolean|string}} Object = same/altered payload,
* false = suppress action,
* string = error
*/
export function inviteCheck({ export function inviteCheck({
core, server, socket, payload, core, server, socket, payload,
}) { }) {
@ -243,7 +285,15 @@ export function inviteCheck({
return payload; return payload;
} }
// shadow-prevent all whispers from muzzled users /**
* Executes every time an incoming chat command is invoked;
* shadow-prevent all whispers from muzzled users
* @param {Object} env - Enviroment object with references to core, server, socket & payload
* @public
* @return {{Object|boolean|string}} Object = same/altered payload,
* false = suppress action,
* string = error
*/
export function whisperCheck({ export function whisperCheck({
core, server, socket, payload, core, server, socket, payload,
}) { }) {
@ -304,11 +354,20 @@ export function whisperCheck({
return payload; return payload;
} }
// export const requiredData = ['nick']; /**
* Module meta information
* @public
* @typedef {Object} dumb/info
* @property {string} name - Module command name
* @property {string} category - Module category name
* @property {string} description - Information about module
* @property {string} usage - Information about module usage
*/
export const info = { export const info = {
name: 'dumb', name: 'dumb',
category: 'moderators',
description: 'Globally shadow mute a connection. Optional allies array will see muted messages.', description: 'Globally shadow mute a connection. Optional allies array will see muted messages.',
aliases: ['muzzle', 'mute'],
usage: ` usage: `
API: { cmd: 'dumb', nick: '<target nick>', allies: ['<optional nick array>', ...] }`, API: { cmd: 'dumb', nick: '<target nick>', allies: ['<optional nick array>', ...] }`,
}; };
info.aliases = ['muzzle', 'mute'];

View File

@ -1,21 +1,37 @@
/* /**
Description: Forces a change on the target socket's nick color * @author Marzavec ( https://github.com/marzavec )
*/ * @summary Color a user
* @version 1.0.0
* @description Forces a user nick to become a certain color
* @module forcecolor
*/
import { import {
isModerator, isModerator,
getUserDetails, getUserDetails,
} from '../utility/_UAC'; } from '../utility/_UAC.js';
import { import {
Errors, Errors,
} from '../utility/_Constants'; } from '../utility/_Constants.js';
import { import {
findUser, findUser,
} from '../utility/_Channels'; } from '../utility/_Channels.js';
/**
* Validate a string as a valid hex color string
* @param {string} color - Color string to validate
* @private
* @todo Move into utility module
* @return {boolean}
*/
const verifyColor = (color) => /(^[0-9A-F]{6}$)|(^[0-9A-F]{3}$)/i.test(color); const verifyColor = (color) => /(^[0-9A-F]{6}$)|(^[0-9A-F]{3}$)/i.test(color);
// module main /**
* Executes when invoked by a remote client
* @param {Object} env - Enviroment object with references to core, server, socket & payload
* @public
* @return {void}
*/
export async function run({ export async function run({
server, socket, payload, server, socket, payload,
}) { }) {
@ -24,7 +40,7 @@ export async function run({
return server.police.frisk(socket.address, 10); return server.police.frisk(socket.address, 10);
} }
const channel = socket.channel; const { channel } = socket;
if (typeof payload.channel === 'undefined') { if (typeof payload.channel === 'undefined') {
payload.channel = channel; payload.channel = channel;
} }
@ -87,12 +103,25 @@ export async function run({
return true; return true;
} }
// module hook functions /**
* Automatically executes once after server is ready to register this modules hooks
* @param {Object} server - Reference to server enviroment object
* @public
* @return {void}
*/
export function initHooks(server) { export function initHooks(server) {
server.registerHook('in', 'chat', this.colorCheck.bind(this), 20); server.registerHook('in', 'chat', this.colorCheck.bind(this), 20);
} }
// hooks chat commands checking for /whisper /**
* Executes every time an incoming chat command is invoked;
* hooks chat commands checking for /forcecolor
* @param {Object} env - Enviroment object with references to core, server, socket & payload
* @public
* @return {{Object|boolean|string}} Object = same/altered payload,
* false = suppress action,
* string = error
*/
export function colorCheck({ export function colorCheck({
core, server, socket, payload, core, server, socket, payload,
}) { }) {
@ -143,10 +172,26 @@ export function colorCheck({
return payload; return payload;
} }
// module meta /**
* The following payload properties are required to invoke this module:
* "nick", "color"
* @public
* @typedef {Array} forcecolor/requiredData
*/
export const requiredData = ['nick', 'color']; export const requiredData = ['nick', 'color'];
/**
* Module meta information
* @public
* @typedef {Object} forcecolor/info
* @property {string} name - Module command name
* @property {string} category - Module category name
* @property {string} description - Information about module
* @property {string} usage - Information about module usage
*/
export const info = { export const info = {
name: 'forcecolor', name: 'forcecolor',
category: 'moderators',
description: 'Forces a user nick to become a certain color', description: 'Forces a user nick to become a certain color',
usage: ` usage: `
API: { cmd: 'forcecolor', nick: '<target nick>', color: '<color as hex>' } API: { cmd: 'forcecolor', nick: '<target nick>', color: '<color as hex>' }

View File

@ -1,22 +1,29 @@
/* eslint no-console: 0 */ /**
* @author Marzavec ( https://github.com/marzavec )
/* * @summary Give da boot
Description: Forces a change on the target(s) socket's channel, then broadcasts event * @version 1.0.0
*/ * @description Silently forces target client(s) into another channel
* @module kick
*/
import { import {
isModerator, isModerator,
levels, levels,
getUserDetails, getUserDetails,
} from '../utility/_UAC'; } from '../utility/_UAC.js';
import { import {
Errors, Errors,
} from '../utility/_Constants'; } from '../utility/_Constants.js';
import { import {
findUsers, findUsers,
} from '../utility/_Channels'; } from '../utility/_Channels.js';
// module main /**
* Executes when invoked by a remote client
* @param {Object} env - Enviroment object with references to core, server, socket & payload
* @public
* @return {void}
*/
export async function run({ export async function run({
core, server, socket, payload, core, server, socket, payload,
}) { }) {
@ -127,9 +134,18 @@ export async function run({
return true; return true;
} }
// export const requiredData = ['nick']; /**
* Module meta information
* @public
* @typedef {Object} kick/info
* @property {string} name - Module command name
* @property {string} category - Module category name
* @property {string} description - Information about module
* @property {string} usage - Information about module usage
*/
export const info = { export const info = {
name: 'kick', name: 'kick',
category: 'moderators',
description: 'Silently forces target client(s) into another channel. `nick` may be string or array of strings', description: 'Silently forces target client(s) into another channel. `nick` may be string or array of strings',
usage: ` usage: `
API: { cmd: 'kick', nick: '<target nick>', to: '<optional target channel>' }`, API: { cmd: 'kick', nick: '<target nick>', to: '<optional target channel>' }`,

View File

@ -1,136 +0,0 @@
/*
Description: Removes the target socket from the current channel and forces a join event in another
@deprecated This module will be removed or replaced
*/
import {
isModerator,
getUserDetails,
} from '../utility/_UAC';
// module main
export async function run({ server, socket, payload }) {
// increase rate limit chance and ignore if not admin or mod
if (!isModerator(socket.level)) {
return server.police.frisk(socket.address, 10);
}
// check user input
if (typeof payload.nick !== 'string' || typeof payload.channel !== 'string') {
return true;
}
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: payload.nick });
if (badClients.length === 0) {
return server.reply({
cmd: 'warn', // @todo Add numeric error code as `id`
text: 'Could not find user in channel',
channel: socket.channel, // @todo Multichannel
}, socket);
}
const badClient = badClients[0];
if (badClient.level >= socket.level) {
return server.reply({
cmd: 'warn', // @todo Add numeric error code as `id`
text: 'Cannot move other users of the same level, how rude',
channel: socket.channel, // @todo Multichannel
}, socket);
}
const currentNick = badClient.nick.toLowerCase();
const userExists = server.findSockets({
channel: payload.channel,
nick: (targetNick) => targetNick.toLowerCase() === currentNick,
});
if (userExists.length > 0) {
// That nickname is already in that channel
return true;
}
const peerList = server.findSockets({ channel: socket.channel });
if (peerList.length > 1) {
for (let i = 0, l = peerList.length; i < l; i += 1) {
server.reply({
cmd: 'onlineRemove',
userid: peerList[i].userid,
nick: peerList[i].nick,
channel: socket.channel, // @todo Multichannel
}, badClient);
if (badClient.nick !== peerList[i].nick) {
server.reply({
cmd: 'onlineRemove',
userid: badClient.userid,
nick: badClient.nick,
channel: socket.channel, // @todo Multichannel
}, peerList[i]);
}
}
}
const newPeerList = server.findSockets({ channel: payload.channel });
const moveAnnouncement = {
...getUserDetails(badClient),
...{
cmd: 'onlineAdd',
channel: payload.channel, // @todo Multichannel
},
};
const nicks = [];
const users = [];
for (let i = 0, l = newPeerList.length; i < l; i += 1) {
server.reply(moveAnnouncement, newPeerList[i]);
nicks.push(newPeerList[i].nick); /* @legacy */
users.push({
...{
channel: payload.channel,
isme: false,
},
...getUserDetails(newPeerList[i]),
});
}
nicks.push(badClient.nick); /* @legacy */
users.push({
...{
isme: true,
},
...getUserDetails(badClient),
});
server.reply({
cmd: 'onlineSet',
nicks, /* @legacy */
users,
channel: payload.channel, // @todo Multichannel (?)
}, badClient);
badClient.channel = payload.channel;
server.broadcast({
cmd: 'info',
text: `${badClient.nick} was moved into ?${payload.channel}`,
channel: payload.channel, // @todo Multichannel
}, { channel: payload.channel });
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>' }`,
};

View File

@ -1,22 +1,35 @@
/* eslint no-param-reassign: 0 */ /* eslint no-param-reassign: 0 */
/* /**
* Description: Pardon a dumb user to be able to speak again * @author OpSimple ( https://github.com/OpSimple )
* Author: simple * @summary Unmuzzle a user
* @version 1.0.0
* @description Pardon a dumb user to be able to speak again
* @module speak
*/ */
import { import {
isModerator, isModerator,
} from '../utility/_UAC'; } from '../utility/_UAC.js';
// module constructor /**
* Automatically executes once after server is ready
* @param {Object} core - Reference to core enviroment object
* @public
* @return {void}
*/
export function init(core) { export function init(core) {
if (typeof core.muzzledHashes === 'undefined') { if (typeof core.muzzledHashes === 'undefined') {
core.muzzledHashes = {}; core.muzzledHashes = {};
} }
} }
// module main /**
* Executes when invoked by a remote client
* @param {Object} env - Enviroment object with references to core, server, socket & payload
* @public
* @return {void}
*/
export async function run({ export async function run({
core, server, socket, payload, core, server, socket, payload,
}) { }) {
@ -74,10 +87,20 @@ export async function run({
return true; return true;
} }
/**
* Module meta information
* @public
* @typedef {Object} speak/info
* @property {string} name - Module command name
* @property {string} category - Module category name
* @property {string} description - Information about module
* @property {string} usage - Information about module usage
*/
export const info = { export const info = {
name: 'speak', name: 'speak',
category: 'moderators',
description: 'Pardon a dumb user to be able to speak again', description: 'Pardon a dumb user to be able to speak again',
aliases: ['unmuzzle', 'unmute'],
usage: ` usage: `
API: { cmd: 'speak', ip/hash: '<target ip or hash' }`, API: { cmd: 'speak', ip/hash: '<target ip or hash' }`,
}; };
info.aliases = ['unmuzzle', 'unmute'];

View File

@ -1,14 +1,21 @@
/* eslint no-console: 0 */ /**
* @author Marzavec ( https://github.com/marzavec )
/* * @summary Unban a user
Description: Removes a target ip from the ratelimiter * @version 1.0.0
*/ * @description Un-bans target user by ip or hash
* @module unban
*/
import { import {
isModerator, isModerator,
} from '../utility/_UAC'; } from '../utility/_UAC.js';
// module main /**
* Executes when invoked by a remote client
* @param {Object} env - Enviroment object with references to core, server, socket & payload
* @public
* @return {void}
*/
export async function run({ export async function run({
core, server, socket, payload, core, server, socket, payload,
}) { }) {
@ -66,9 +73,19 @@ export async function run({
return true; return true;
} }
/**
* Module meta information
* @public
* @typedef {Object} unban/info
* @property {string} name - Module command name
* @property {string} category - Module category name
* @property {string} description - Information about module
* @property {string} usage - Information about module usage
*/
export const info = { export const info = {
name: 'unban', name: 'unban',
description: 'Removes target ip from the ratelimiter', category: 'moderators',
description: 'Un-bans target user by ip or hash',
usage: ` usage: `
API: { cmd: 'unban', ip/hash: '<target ip or hash>' }`, API: { cmd: 'unban', ip/hash: '<target ip or hash>' }`,
}; };

View File

@ -1,14 +1,21 @@
/* eslint no-console: 0 */ /**
* @author Marzavec ( https://github.com/marzavec )
/* * @summary Released them from the void
Description: Clears all bans and ratelimits * @version 1.0.0
*/ * @description Clears all banned ip addresses
* @module unbanall
*/
import { import {
isModerator, isModerator,
} from '../utility/_UAC'; } from '../utility/_UAC.js';
// module main /**
* Executes when invoked by a remote client
* @param {Object} env - Enviroment object with references to core, server, socket & payload
* @public
* @return {void}
*/
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 // increase rate limit chance and ignore if not admin or mod
if (!isModerator(socket.level)) { if (!isModerator(socket.level)) {
@ -39,8 +46,18 @@ export async function run({ core, server, socket }) {
return true; return true;
} }
/**
* Module meta information
* @public
* @typedef {Object} unbanall/info
* @property {string} name - Module command name
* @property {string} category - Module category name
* @property {string} description - Information about module
* @property {string} usage - Information about module usage
*/
export const info = { export const info = {
name: 'unbanall', name: 'unbanall',
category: 'moderators',
description: 'Clears all banned ip addresses', description: 'Clears all banned ip addresses',
usage: ` usage: `
API: { cmd: 'unbanall' }`, API: { cmd: 'unbanall' }`,

View File

@ -1,6 +1,14 @@
/**
* @author Marzavec ( https://github.com/marzavec )
* @summary Channel helper
* @version 1.0.0
* @description Functions to assist with channel manipulation
* @module Channels
*/
import { import {
Errors, Errors,
} from './_Constants'; } from './_Constants.js';
/** /**
* Checks if a client can join `channel`, returns numeric error code or true if * Checks if a client can join `channel`, returns numeric error code or true if
@ -10,12 +18,13 @@ import {
* @param {object} socket Target client to evaluate * @param {object} socket Target client to evaluate
* @return {boolean||error id} * @return {boolean||error id}
*/ */
// eslint-disable-next-line no-unused-vars
export function canJoinChannel(channel, socket) { export function canJoinChannel(channel, socket) {
if (typeof channel !== 'string') return Errors.Channel.INVALID_NAME; if (typeof channel !== 'string') return Errors.Channel.INVALID_NAME;
if (channel === '') return Errors.Channel.INVALID_NAME; if (channel === '') return Errors.Channel.INVALID_NAME;
if (channel.length > 120) return Errors.Channel.INVALID_LENGTH; if (channel.length > 120) return Errors.Channel.INVALID_LENGTH;
if (typeof socket.banned !== 'undefined' && socket.banned) return Errors.Channel.DEY_BANNED;
return true; return true;
} }
@ -28,9 +37,9 @@ export function canJoinChannel(channel, socket) {
* @return {object} * @return {object}
*/ */
export function getChannelSettings(config, channel) { export function getChannelSettings(config, channel) {
if (typeof config.channels !== 'undefined') { if (typeof config.permissions !== 'undefined') {
if (typeof config.channels[channel] !== 'undefined') { if (typeof config.permissions[channel] !== 'undefined') {
return config.channels[channel]; return config.permissions[channel];
} }
} }
@ -83,3 +92,17 @@ export function findUsers(server, payload, limit = 0) {
export function findUser(server, payload) { export function findUser(server, payload) {
return findUsers(server, payload, 1)[0] || false; return findUsers(server, payload, 1)[0] || false;
} }
/**
* Check if the target socket's userid is already in target channel
* @param {MainServer} server Main server reference
* @param {string} channel Target channel
* @param {object} socket Target client to evaluate
* @return {boolean||object}
*/
export function socketInChannel(server, channel, socket) {
return findUser(server, {
channel,
userid: socket.userid,
});
}

View File

@ -1,14 +1,23 @@
/**
* @author Marzavec ( https://github.com/marzavec )
* @summary Error ID list
* @version 1.0.0
* @description Exports an object that hold common global error IDs
* @module Constants
*/
/* Base error ranges */ /* Base error ranges */
const GlobalErrors = 10; const GlobalErrors = 10;
const JoinErrors = 20; const JoinErrors = 20;
const ChannelErrors = 30; const ChannelErrors = 30;
const InviteErrors = 40; const InviteErrors = 40;
const SessionErrors = 50;
/** /**
* Holds the numeric id values for each error type * Holds the numeric id values for each error type
* @typedef {object} Errors * @typedef {object} Errors
*/ */
exports.Errors = { export const Errors = {
Global: { Global: {
RATELIMIT: GlobalErrors + 1, RATELIMIT: GlobalErrors + 1,
UNKNOWN_USER: GlobalErrors + 2, UNKNOWN_USER: GlobalErrors + 2,
@ -25,9 +34,16 @@ exports.Errors = {
Channel: { Channel: {
INVALID_NAME: ChannelErrors + 1, INVALID_NAME: ChannelErrors + 1,
INVALID_LENGTH: ChannelErrors + 2, INVALID_LENGTH: ChannelErrors + 2,
DEY_BANNED: ChannelErrors + 3,
}, },
Invite: { Invite: {
RATELIMIT: InviteErrors + 1, RATELIMIT: InviteErrors + 1,
}, },
Session: {
BAD_SESSION: SessionErrors + 1,
},
}; };
export default Errors;

View File

@ -1,9 +1,17 @@
/* eslint no-param-reassign: 0 */ /* eslint no-param-reassign: 0 */
/**
* @author Marzavec ( https://github.com/marzavec )
* @summary Support functions for old clients
* @version 1.0.0
* @description Functions to bridge the older v1 clients with the latest protocol
* @module LegacyFunctions
*/
import { import {
isAdmin, isAdmin,
isModerator, isModerator,
} from './_UAC'; } from './_UAC.js';
/** /**
* Marks the socket as using the legacy protocol and * Marks the socket as using the legacy protocol and

View File

@ -4,14 +4,16 @@
* @property {Object} levels - Defines labels for default permission ranges * @property {Object} levels - Defines labels for default permission ranges
* @author MinusGix ( https://github.com/MinusGix ) * @author MinusGix ( https://github.com/MinusGix )
* @version v1.0.0 * @version v1.0.0
* @license WTFPL ( http://www.wtfpl.net/txt/copying/ ) * @module UAC
*/ */
import { import {
getChannelSettings, getChannelSettings,
} from './_Channels'; } from './_Channels.js';
const crypto = require('crypto'); const {
createHash,
} = await import('crypto');
/** /**
* Object defining labels for default permission ranges * Object defining labels for default permission ranges
@ -106,12 +108,13 @@ export function getUserDetails(socket) {
return { return {
nick: socket.nick, nick: socket.nick,
trip: socket.trip || '', trip: socket.trip || '',
uType: socket.uType, uType: socket.uType, /* @legacy */
hash: socket.hash, hash: socket.hash,
level: socket.level, level: socket.level,
userid: socket.userid, userid: socket.userid,
isBot: socket.isBot, isBot: socket.isBot,
color: socket.color, color: socket.color,
online: true,
}; };
} }
@ -132,11 +135,12 @@ export function verifyNickname(nick) {
* or a blank string * or a blank string
* @public * @public
* @param {string} pass User's password * @param {string} pass User's password
* @param {buffer} salt Server salt data
* @param {string} config Server config object * @param {string} config Server config object
* @param {string} channel Channel-level permissions check * @param {string} channel Channel-level permissions check
* @return {string} * @return {string}
*/ */
export function getUserPerms(pass, config, channel) { export function getUserPerms(pass, salt, config, channel) {
if (!pass) { if (!pass) {
return { return {
trip: '', trip: '',
@ -144,8 +148,8 @@ export function getUserPerms(pass, config, channel) {
}; };
} }
const sha = crypto.createHash('sha256'); const sha = createHash('sha256');
sha.update(pass + config.tripSalt); sha.update(pass + salt);
const trip = sha.digest('base64').substr(0, 6); const trip = sha.digest('base64').substr(0, 6);
// check if user is global admin // check if user is global admin
@ -159,7 +163,7 @@ export function getUserPerms(pass, config, channel) {
let level = levels.default; let level = levels.default;
// check if user is global mod // check if user is global mod
config.mods.forEach((mod) => { // eslint-disable-line consistent-return config.globalMods.forEach((mod) => { // eslint-disable-line consistent-return
if (trip === mod.trip) { if (trip === mod.trip) {
level = levels.moderator; level = levels.moderator;
} }

View File

@ -1,48 +0,0 @@
You can programmatically access hack.chat using the following commands via a websocket. A list of wrappers written for accessing hack.chat can be found [here](https://github.com/hack-chat/3rd-party-software-list#libraries).
The commands are to be sent through a websocket to the URL `wss://hack.chat/chat-ws` (everything sent and received are JSON). If you are sending messages locally or to another domain, replace 'hack.chat' with the respective domain. If you're running your own instance of hack.chat, you can retain backwards-compatibility in order to ensure that software created for the main server will work on yours too.
All commands sent must be JSON objects with the command specified in the `"cmd"` key. For example:
```json
{
"cmd": "join",
"channel": "programming",
"nick": "john#doe"
}
```
hack.chat has three permission levels. When you access a command, hack.chat automatically knows your permission level from your trip code. The lowest permission level is `user`. `mod` is above `user`, so it can access `user` commands in addition to `mod` commands. `admin` is similarly above `mod`.
# `user`
|Command|Parameters|Explanation|
|-------|----------|-----------|
|`changenick`|`nick`|Changes the current connection's nickname.|
|`chat`|`text`|This broadcasts `text` to the channel the user is connected to.|
|`disconnect`||An event handler or forced disconnect.|
|`invite`|`nick`|Generates a pseudo-unique channel name and passes it to both the calling user and `nick`.|
|`join`|`channel`, `nick`|Places the calling socket into the target channel with the target nick and broadcasts the event to the channel.|
|`morestats`||Sends back the current server's stats to the calling client.|
|`move`|`channel`|This will change the current channel to `channel`.|
|`stats`||Sends back legacy server stats to the calling client. Use `morestats` when possible.|
|`help`|`category` or `command`|Gives documentation programmatically. If `category` (the permission level, such as `mod`) is sent, a list of commands available to that permission level will be sent back (as a `string` and not an `array`). This list only includes what is unique to that category and not every command a user with that permission level could perform. If `command` (e.g., `chat`) is sent, a description of the command will be sent back.|
# `mod`
|Command|Parameters|Explanation|
|-------|----------|-----------|
|`ban`|`nick`|Disconnects the target nickname in the same channel as the calling socket and adds it to the rate limiter.|
|`kick`|`nick`|Silently forces target client(s) into another channel. `nick` may be `string` or `array` of `string`s.|
|`unban`|`ip` or `hash`|Removes the target ip from the rate limiter.|
|`dumb`|`nick`|Mutes a user's (spammer's) texts such that it is displayable to the user only.|
|`speak`|`ip` or `hash`|Unmutes the user's (spammer's) texts and makes it displayable to everyone again.|
# `admin`
|Command|Parameters|Explanation|
|-------|----------|-----------|
|`addmod`|`nick`|Adds the target trip to the config as a mod and upgrades the socket type.|
|`listusers`||Outputs all current channels and sockets in those channels.|
|`reload`||(Re)loads any new commands into memory and outputs errors, if any.|
|`saveconfig`||Saves the current config.|
|`shout`|`text`|Displays the passed text to each client connected.|

View File

@ -0,0 +1,159 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>JSDoc: Source: admin/addmod.js</title>
<script src="scripts/prettify/prettify.js"> </script>
<script src="scripts/prettify/lang-css.js"> </script>
<!--[if lt IE 9]>
<script src="//html5shiv.googlecode.com/svn/trunk/html5.js"></script>
<![endif]-->
<link type="text/css" rel="stylesheet" href="styles/prettify-tomorrow.css">
<link type="text/css" rel="stylesheet" href="styles/jsdoc-default.css">
</head>
<body>
<div id="main">
<h1 class="page-title">Source: admin/addmod.js</h1>
<section>
<article>
<pre class="prettyprint source linenums"><code>/**
* @author Marzavec ( https://github.com/marzavec )
* @summary Create a new mod trip
* @version 1.0.0
* @description Adds target trip to the config as a mod and upgrades the socket type
* @module addmod
*/
import {
isAdmin,
isModerator,
levels,
getUserDetails,
} from '../utility/_UAC.js';
/**
* Executes when invoked by a remote client
* @param {Object} env - Enviroment object with references to core, server, socket &amp; payload
* @public
* @return {void}
*/
export async function run({
core, server, socket, payload,
}) {
// increase rate limit chance and ignore if not admin
if (!isAdmin(socket.level)) {
return server.police.frisk(socket.address, 20);
}
// add new trip to config
core.appConfig.data.globalMods.push({ trip: payload.trip });
// find targets current connections
const newMod = server.findSockets({ trip: payload.trip });
if (newMod.length !== 0) {
// build update notice with new privileges
const updateNotice = {
...getUserDetails(newMod[0]),
...{
cmd: 'updateUser',
uType: 'mod', // @todo use legacyLevelToLabel from _LegacyFunctions.js
level: levels.moderator,
},
};
for (let i = 0, l = newMod.length; i &lt; l; i += 1) {
// upgrade privileges
newMod[i].uType = 'mod'; // @todo use legacyLevelToLabel from _LegacyFunctions.js
newMod[i].level = levels.moderator;
// inform new mod
server.send({
cmd: 'info',
text: 'You are now a mod.',
channel: newMod[i].channel, // @todo Multichannel
}, newMod[i]);
// notify channel
server.broadcast({
...updateNotice,
...{
channel: newMod[i].channel,
},
}, { channel: newMod[i].channel });
}
}
// return success message
server.reply({
cmd: 'info',
text: `Added mod trip: ${payload.trip}, remember to run 'saveconfig' to make it permanent`,
channel: socket.channel, // @todo Multichannel
}, socket);
// notify all mods
server.broadcast({
cmd: 'info',
text: `Added mod: ${payload.trip}`,
channel: false, // @todo Multichannel, false for global info
}, { level: isModerator });
return true;
}
/**
* The following payload properties are required to invoke this module:
* "trip"
* @public
* @typedef {Array} addmod/requiredData
*/
export const requiredData = ['trip'];
/**
* Module meta information
* @public
* @typedef {Object} addmod/info
* @property {string} name - Module command name
* @property {string} category - Module category name
* @property {string} description - Information about module
* @property {string} usage - Information about module usage
*/
export const info = {
name: 'addmod',
category: 'admin',
description: 'Adds target trip to the config as a mod and upgrades the socket type',
usage: `
API: { cmd: 'addmod', trip: '&lt;target trip>' }`,
};
</code></pre>
</article>
</section>
</div>
<nav>
<h2><a href="index.html">Home</a></h2><h3>Modules</h3><ul><li><a href="module-addmod.html">addmod</a></li><li><a href="module-ban.html">ban</a></li><li><a href="module-changecolor.html">changecolor</a></li><li><a href="module-changenick.html">changenick</a></li><li><a href="module-chat.html">chat</a></li><li><a href="module-disconnect.html">disconnect</a></li><li><a href="module-dumb.html">dumb</a></li><li><a href="module-emote.html">emote</a></li><li><a href="module-forcecolor.html">forcecolor</a></li><li><a href="module-help.html">help</a></li><li><a href="module-invite.html">invite</a></li><li><a href="module-join.html">join</a></li><li><a href="module-kick.html">kick</a></li><li><a href="module-listusers.html">listusers</a></li><li><a href="module-morestats.html">morestats</a></li><li><a href="module-ping.html">ping</a></li><li><a href="module-reload.html">reload</a></li><li><a href="module-removemod.html">removemod</a></li><li><a href="module-saveconfig.html">saveconfig</a></li><li><a href="module-session.html">session</a></li><li><a href="module-shout.html">shout</a></li><li><a href="module-socketreply.html">socketreply</a></li><li><a href="module-speak.html">speak</a></li><li><a href="module-stats.html">stats</a></li><li><a href="module-unban.html">unban</a></li><li><a href="module-unbanall.html">unbanall</a></li><li><a href="module-whisper.html">whisper</a></li></ul>
</nav>
<br class="clear">
<footer>
Documentation generated by <a href="https://github.com/jsdoc/jsdoc">JSDoc 3.6.6</a> on Wed Jun 22 2022 10:04:25 GMT-0500 (Central Daylight Time)
</footer>
<script> prettyPrint(); </script>
<script src="scripts/linenumber.js"> </script>
</body>
</html>

View File

@ -0,0 +1,128 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>JSDoc: Source: admin/listusers.js</title>
<script src="scripts/prettify/prettify.js"> </script>
<script src="scripts/prettify/lang-css.js"> </script>
<!--[if lt IE 9]>
<script src="//html5shiv.googlecode.com/svn/trunk/html5.js"></script>
<![endif]-->
<link type="text/css" rel="stylesheet" href="styles/prettify-tomorrow.css">
<link type="text/css" rel="stylesheet" href="styles/jsdoc-default.css">
</head>
<body>
<div id="main">
<h1 class="page-title">Source: admin/listusers.js</h1>
<section>
<article>
<pre class="prettyprint source linenums"><code>/* eslint no-unused-vars: 0 */
/* eslint no-restricted-syntax: 0 */
/* eslint guard-for-in: 0 */
/**
* @author Marzavec ( https://github.com/marzavec )
* @summary Show users and channels
* @version 1.0.0
* @description Outputs all current channels and sockets in those channels
* @module listusers
*/
import {
isAdmin,
} from '../utility/_UAC.js';
/**
* Executes when invoked by a remote client
* @param {Object} env - Enviroment object with references to core, server, socket &amp; payload
* @public
* @return {void}
*/
export async function run({ server, socket }) {
// increase rate limit chance and ignore if not admin
if (!isAdmin(socket.level)) {
return server.police.frisk(socket.address, 20);
}
// find all users currently in a channel
const currentUsers = server.findSockets({
channel: (channel) => true,
});
// compile channel and user list
const channels = {};
for (let i = 0, j = currentUsers.length; i &lt; 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}`,
);
}
// build output
const lines = [];
for (const channel in channels) {
lines.push(`?${channel} ${channels[channel].join(', ')}`);
}
// send reply
server.reply({
cmd: 'info',
text: lines.join('\n'),
channel: socket.channel, // @todo Multichannel
}, socket);
return true;
}
/**
* Module meta information
* @public
* @typedef {Object} listusers/info
* @property {string} name - Module command name
* @property {string} category - Module category name
* @property {string} description - Information about module
* @property {string} usage - Information about module usage
*/
export const info = {
name: 'listusers',
category: 'admin',
description: 'Outputs all current channels and sockets in those channels',
usage: `
API: { cmd: 'listusers' }`,
};
</code></pre>
</article>
</section>
</div>
<nav>
<h2><a href="index.html">Home</a></h2><h3>Modules</h3><ul><li><a href="module-addmod.html">addmod</a></li><li><a href="module-ban.html">ban</a></li><li><a href="module-changecolor.html">changecolor</a></li><li><a href="module-changenick.html">changenick</a></li><li><a href="module-chat.html">chat</a></li><li><a href="module-disconnect.html">disconnect</a></li><li><a href="module-dumb.html">dumb</a></li><li><a href="module-emote.html">emote</a></li><li><a href="module-forcecolor.html">forcecolor</a></li><li><a href="module-help.html">help</a></li><li><a href="module-invite.html">invite</a></li><li><a href="module-join.html">join</a></li><li><a href="module-kick.html">kick</a></li><li><a href="module-listusers.html">listusers</a></li><li><a href="module-morestats.html">morestats</a></li><li><a href="module-ping.html">ping</a></li><li><a href="module-reload.html">reload</a></li><li><a href="module-removemod.html">removemod</a></li><li><a href="module-saveconfig.html">saveconfig</a></li><li><a href="module-session.html">session</a></li><li><a href="module-shout.html">shout</a></li><li><a href="module-socketreply.html">socketreply</a></li><li><a href="module-speak.html">speak</a></li><li><a href="module-stats.html">stats</a></li><li><a href="module-unban.html">unban</a></li><li><a href="module-unbanall.html">unbanall</a></li><li><a href="module-whisper.html">whisper</a></li></ul>
</nav>
<br class="clear">
<footer>
Documentation generated by <a href="https://github.com/jsdoc/jsdoc">JSDoc 3.6.6</a> on Wed Jun 22 2022 10:04:25 GMT-0500 (Central Daylight Time)
</footer>
<script> prettyPrint(); </script>
<script src="scripts/linenumber.js"> </script>
</body>
</html>

View File

@ -0,0 +1,122 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>JSDoc: Source: admin/reload.js</title>
<script src="scripts/prettify/prettify.js"> </script>
<script src="scripts/prettify/lang-css.js"> </script>
<!--[if lt IE 9]>
<script src="//html5shiv.googlecode.com/svn/trunk/html5.js"></script>
<![endif]-->
<link type="text/css" rel="stylesheet" href="styles/prettify-tomorrow.css">
<link type="text/css" rel="stylesheet" href="styles/jsdoc-default.css">
</head>
<body>
<div id="main">
<h1 class="page-title">Source: admin/reload.js</h1>
<section>
<article>
<pre class="prettyprint source linenums"><code>/**
* @author Marzavec ( https://github.com/marzavec )
* @summary Refresh modules
* @version 1.0.0
* @description Allows a remote user to clear and re-import the server command modules
* @module reload
*/
import {
isAdmin,
isModerator,
} from '../utility/_UAC.js';
/**
* Executes when invoked by a remote client
* @param {Object} env - Enviroment object with references to core, server, socket &amp; payload
* @public
* @return {void}
*/
export async function run({
core, server, socket, payload,
}) {
// increase rate limit chance and ignore if not admin
if (!isAdmin(socket.level)) {
return server.police.frisk(socket.address, 20);
}
// do command reload and store results
let loadResult = await core.commands.reloadCommands();
// clear and rebuild all module hooks
server.loadHooks();
// build reply based on reload results
if (loadResult === '') {
loadResult = `Reloaded ${core.commands.commands.length} commands, 0 errors`;
} else {
loadResult = `Reloaded ${core.commands.commands.length} commands, error(s):
${loadResult}`;
}
if (typeof payload.reason !== 'undefined') {
loadResult += `\nReason: ${payload.reason}`;
}
// send results to moderators (which the user using this command is higher than)
server.broadcast({
cmd: 'info',
text: loadResult,
channel: false, // @todo Multichannel, false for global
}, { level: isModerator });
return true;
}
/**
* Module meta information
* @public
* @typedef {Object} reload/info
* @property {string} name - Module command name
* @property {string} category - Module category name
* @property {string} description - Information about module
* @property {string} usage - Information about module usage
*/
export const info = {
name: 'reload',
category: 'admin',
description: 'Allows a remote user to clear and re-import the server command modules',
usage: `
API: { cmd: 'reload', reason: '&lt;optional reason append>' }`,
};
</code></pre>
</article>
</section>
</div>
<nav>
<h2><a href="index.html">Home</a></h2><h3>Modules</h3><ul><li><a href="module-addmod.html">addmod</a></li><li><a href="module-ban.html">ban</a></li><li><a href="module-changecolor.html">changecolor</a></li><li><a href="module-changenick.html">changenick</a></li><li><a href="module-chat.html">chat</a></li><li><a href="module-disconnect.html">disconnect</a></li><li><a href="module-dumb.html">dumb</a></li><li><a href="module-emote.html">emote</a></li><li><a href="module-forcecolor.html">forcecolor</a></li><li><a href="module-help.html">help</a></li><li><a href="module-invite.html">invite</a></li><li><a href="module-join.html">join</a></li><li><a href="module-kick.html">kick</a></li><li><a href="module-listusers.html">listusers</a></li><li><a href="module-morestats.html">morestats</a></li><li><a href="module-ping.html">ping</a></li><li><a href="module-reload.html">reload</a></li><li><a href="module-removemod.html">removemod</a></li><li><a href="module-saveconfig.html">saveconfig</a></li><li><a href="module-session.html">session</a></li><li><a href="module-shout.html">shout</a></li><li><a href="module-socketreply.html">socketreply</a></li><li><a href="module-speak.html">speak</a></li><li><a href="module-stats.html">stats</a></li><li><a href="module-unban.html">unban</a></li><li><a href="module-unbanall.html">unbanall</a></li><li><a href="module-whisper.html">whisper</a></li></ul>
</nav>
<br class="clear">
<footer>
Documentation generated by <a href="https://github.com/jsdoc/jsdoc">JSDoc 3.6.6</a> on Wed Jun 22 2022 10:04:25 GMT-0500 (Central Daylight Time)
</footer>
<script> prettyPrint(); </script>
<script src="scripts/linenumber.js"> </script>
</body>
</html>

View File

@ -0,0 +1,164 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>JSDoc: Source: admin/removemod.js</title>
<script src="scripts/prettify/prettify.js"> </script>
<script src="scripts/prettify/lang-css.js"> </script>
<!--[if lt IE 9]>
<script src="//html5shiv.googlecode.com/svn/trunk/html5.js"></script>
<![endif]-->
<link type="text/css" rel="stylesheet" href="styles/prettify-tomorrow.css">
<link type="text/css" rel="stylesheet" href="styles/jsdoc-default.css">
</head>
<body>
<div id="main">
<h1 class="page-title">Source: admin/removemod.js</h1>
<section>
<article>
<pre class="prettyprint source linenums"><code>/**
* @author Marzavec ( https://github.com/marzavec )
* @summary Removes a mod
* @version 1.0.0
* @description Removes target trip from the config as a mod and downgrades the socket type
* @module removemod
*/
import {
isAdmin,
isModerator,
levels,
getUserDetails,
} from '../utility/_UAC.js';
/**
* Executes when invoked by a remote client
* @param {Object} env - Enviroment object with references to core, server, socket &amp; payload
* @public
* @return {void}
*/
export async function run({
core, server, socket, payload,
}) {
// increase rate limit chance and ignore if not admin
if (!isAdmin(socket.level)) {
return server.police.frisk(socket.address, 20);
}
// remove trip from config
// eslint-disable-next-line no-param-reassign
core.appConfig.data.globalMods = core.appConfig.data.globalMods.filter(
(mod) => mod.trip !== payload.trip,
);
// find targets current connections
const targetMod = server.findSockets({ trip: payload.trip });
if (targetMod.length !== 0) {
// build update notice with new privileges
const updateNotice = {
...getUserDetails(targetMod[0]),
...{
cmd: 'updateUser',
uType: 'user', // @todo use legacyLevelToLabel from _LegacyFunctions.js
level: levels.default,
},
};
for (let i = 0, l = targetMod.length; i &lt; l; i += 1) {
// downgrade privileges
targetMod[i].uType = 'user'; /* @legacy */
targetMod[i].level = levels.default;
// inform ex-mod
server.send({
cmd: 'info',
text: 'You are now a user.',
channel: targetMod[i].channel, // @todo Multichannel
}, targetMod[i]);
// notify channel
server.broadcast({
...updateNotice,
...{
channel: targetMod[i].channel,
},
}, { channel: targetMod[i].channel });
}
}
// return success message
server.reply({
cmd: 'info',
text: `Removed mod trip: ${
payload.trip
}, remember to run 'saveconfig' to make it permanent`,
channel: socket.channel, // @todo Multichannel
}, socket);
// notify all mods
server.broadcast({
cmd: 'info',
text: `Removed mod: ${payload.trip}`,
channel: false, // @todo Multichannel, false for global
}, { level: isModerator });
return true;
}
/**
* The following payload properties are required to invoke this module:
* "trip"
* @public
* @typedef {Array} removemod/requiredData
*/
export const requiredData = ['trip'];
/**
* Module meta information
* @public
* @typedef {Object} removemod/info
* @property {string} name - Module command name
* @property {string} category - Module category name
* @property {string} description - Information about module
* @property {string} usage - Information about module usage
*/
export const info = {
name: 'removemod',
category: 'admin',
description: 'Removes target trip from the config as a mod and downgrades the socket type',
usage: `
API: { cmd: 'removemod', trip: '&lt;target trip>' }`,
};
</code></pre>
</article>
</section>
</div>
<nav>
<h2><a href="index.html">Home</a></h2><h3>Modules</h3><ul><li><a href="module-addmod.html">addmod</a></li><li><a href="module-ban.html">ban</a></li><li><a href="module-changecolor.html">changecolor</a></li><li><a href="module-changenick.html">changenick</a></li><li><a href="module-chat.html">chat</a></li><li><a href="module-disconnect.html">disconnect</a></li><li><a href="module-dumb.html">dumb</a></li><li><a href="module-emote.html">emote</a></li><li><a href="module-forcecolor.html">forcecolor</a></li><li><a href="module-help.html">help</a></li><li><a href="module-invite.html">invite</a></li><li><a href="module-join.html">join</a></li><li><a href="module-kick.html">kick</a></li><li><a href="module-listusers.html">listusers</a></li><li><a href="module-morestats.html">morestats</a></li><li><a href="module-ping.html">ping</a></li><li><a href="module-reload.html">reload</a></li><li><a href="module-removemod.html">removemod</a></li><li><a href="module-saveconfig.html">saveconfig</a></li><li><a href="module-session.html">session</a></li><li><a href="module-shout.html">shout</a></li><li><a href="module-socketreply.html">socketreply</a></li><li><a href="module-speak.html">speak</a></li><li><a href="module-stats.html">stats</a></li><li><a href="module-unban.html">unban</a></li><li><a href="module-unbanall.html">unbanall</a></li><li><a href="module-whisper.html">whisper</a></li></ul>
</nav>
<br class="clear">
<footer>
Documentation generated by <a href="https://github.com/jsdoc/jsdoc">JSDoc 3.6.6</a> on Wed Jun 22 2022 10:04:25 GMT-0500 (Central Daylight Time)
</footer>
<script> prettyPrint(); </script>
<script src="scripts/linenumber.js"> </script>
</body>
</html>

View File

@ -0,0 +1,113 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>JSDoc: Source: admin/saveconfig.js</title>
<script src="scripts/prettify/prettify.js"> </script>
<script src="scripts/prettify/lang-css.js"> </script>
<!--[if lt IE 9]>
<script src="//html5shiv.googlecode.com/svn/trunk/html5.js"></script>
<![endif]-->
<link type="text/css" rel="stylesheet" href="styles/prettify-tomorrow.css">
<link type="text/css" rel="stylesheet" href="styles/jsdoc-default.css">
</head>
<body>
<div id="main">
<h1 class="page-title">Source: admin/saveconfig.js</h1>
<section>
<article>
<pre class="prettyprint source linenums"><code>/**
* @author Marzavec ( https://github.com/marzavec )
* @summary Saves the config
* @version 1.0.0
* @description Writes the current config to disk
* @module saveconfig
*/
import {
isAdmin,
isModerator,
} from '../utility/_UAC.js';
/**
* Executes when invoked by a remote client
* @param {Object} env - Enviroment object with references to core, server, socket &amp; payload
* @public
* @return {void}
*/
export async function run({ core, server, socket }) {
// increase rate limit chance and ignore if not admin
if (!isAdmin(socket.level)) {
return server.police.frisk(socket.address, 20);
}
// attempt save, notify of failure
try {
await core.appConfig.write();
} catch (err) {
return server.reply({
cmd: 'warn', // @todo Add numeric error code as `id`
text: 'Failed to save config, check logs.',
channel: socket.channel, // @todo Multichannel
}, socket);
}
// return success message to moderators and admins
server.broadcast({
cmd: 'info',
text: 'Config saved!',
channel: false, // @todo Multichannel
}, { level: isModerator });
return true;
}
/**
* Module meta information
* @public
* @typedef {Object} saveconfig/info
* @property {string} name - Module command name
* @property {string} category - Module category name
* @property {string} description - Information about module
* @property {string} usage - Information about module usage
*/
export const info = {
name: 'saveconfig',
category: 'admin',
description: 'Writes the current config to disk',
usage: `
API: { cmd: 'saveconfig' }`,
};
</code></pre>
</article>
</section>
</div>
<nav>
<h2><a href="index.html">Home</a></h2><h3>Modules</h3><ul><li><a href="module-addmod.html">addmod</a></li><li><a href="module-ban.html">ban</a></li><li><a href="module-changecolor.html">changecolor</a></li><li><a href="module-changenick.html">changenick</a></li><li><a href="module-chat.html">chat</a></li><li><a href="module-disconnect.html">disconnect</a></li><li><a href="module-dumb.html">dumb</a></li><li><a href="module-emote.html">emote</a></li><li><a href="module-forcecolor.html">forcecolor</a></li><li><a href="module-help.html">help</a></li><li><a href="module-invite.html">invite</a></li><li><a href="module-join.html">join</a></li><li><a href="module-kick.html">kick</a></li><li><a href="module-listusers.html">listusers</a></li><li><a href="module-morestats.html">morestats</a></li><li><a href="module-ping.html">ping</a></li><li><a href="module-reload.html">reload</a></li><li><a href="module-removemod.html">removemod</a></li><li><a href="module-saveconfig.html">saveconfig</a></li><li><a href="module-session.html">session</a></li><li><a href="module-shout.html">shout</a></li><li><a href="module-socketreply.html">socketreply</a></li><li><a href="module-speak.html">speak</a></li><li><a href="module-stats.html">stats</a></li><li><a href="module-unban.html">unban</a></li><li><a href="module-unbanall.html">unbanall</a></li><li><a href="module-whisper.html">whisper</a></li></ul>
</nav>
<br class="clear">
<footer>
Documentation generated by <a href="https://github.com/jsdoc/jsdoc">JSDoc 3.6.6</a> on Wed Jun 22 2022 10:04:25 GMT-0500 (Central Daylight Time)
</footer>
<script> prettyPrint(); </script>
<script src="scripts/linenumber.js"> </script>
</body>
</html>

View File

@ -0,0 +1,109 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>JSDoc: Source: admin/shout.js</title>
<script src="scripts/prettify/prettify.js"> </script>
<script src="scripts/prettify/lang-css.js"> </script>
<!--[if lt IE 9]>
<script src="//html5shiv.googlecode.com/svn/trunk/html5.js"></script>
<![endif]-->
<link type="text/css" rel="stylesheet" href="styles/prettify-tomorrow.css">
<link type="text/css" rel="stylesheet" href="styles/jsdoc-default.css">
</head>
<body>
<div id="main">
<h1 class="page-title">Source: admin/shout.js</h1>
<section>
<article>
<pre class="prettyprint source linenums"><code>/**
* @author Marzavec ( https://github.com/marzavec )
* @summary Emit text everywhere
* @version 1.0.0
* @description Displays passed text to every client connected
* @module shout
*/
import {
isAdmin,
} from '../utility/_UAC.js';
/**
* Executes when invoked by a remote client
* @param {Object} env - Enviroment object with references to core, server, socket &amp; payload
* @public
* @return {void}
*/
export async function run({ server, socket, payload }) {
// increase rate limit chance and ignore if not admin
if (!isAdmin(socket.level)) {
return server.police.frisk(socket.address, 20);
}
// send text to all channels
server.broadcast({
cmd: 'info',
text: `Server Notice: ${payload.text}`,
channel: false, // @todo Multichannel, false for global
}, {});
return true;
}
/**
* The following payload properties are required to invoke this module:
* "text"
* @public
* @typedef {Array} shout/requiredData
*/
export const requiredData = ['text'];
/**
* Module meta information
* @public
* @typedef {Object} shout/info
* @property {string} name - Module command name
* @property {string} category - Module category name
* @property {string} description - Information about module
* @property {string} usage - Information about module usage
*/
export const info = {
name: 'shout',
category: 'admin',
description: 'Displays passed text to every client connected',
usage: `
API: { cmd: 'shout', text: '&lt;shout text>' }`,
};
</code></pre>
</article>
</section>
</div>
<nav>
<h2><a href="index.html">Home</a></h2><h3>Modules</h3><ul><li><a href="module-addmod.html">addmod</a></li><li><a href="module-ban.html">ban</a></li><li><a href="module-changecolor.html">changecolor</a></li><li><a href="module-changenick.html">changenick</a></li><li><a href="module-chat.html">chat</a></li><li><a href="module-disconnect.html">disconnect</a></li><li><a href="module-dumb.html">dumb</a></li><li><a href="module-emote.html">emote</a></li><li><a href="module-forcecolor.html">forcecolor</a></li><li><a href="module-help.html">help</a></li><li><a href="module-invite.html">invite</a></li><li><a href="module-join.html">join</a></li><li><a href="module-kick.html">kick</a></li><li><a href="module-listusers.html">listusers</a></li><li><a href="module-morestats.html">morestats</a></li><li><a href="module-ping.html">ping</a></li><li><a href="module-reload.html">reload</a></li><li><a href="module-removemod.html">removemod</a></li><li><a href="module-saveconfig.html">saveconfig</a></li><li><a href="module-session.html">session</a></li><li><a href="module-shout.html">shout</a></li><li><a href="module-socketreply.html">socketreply</a></li><li><a href="module-speak.html">speak</a></li><li><a href="module-stats.html">stats</a></li><li><a href="module-unban.html">unban</a></li><li><a href="module-unbanall.html">unbanall</a></li><li><a href="module-whisper.html">whisper</a></li></ul>
</nav>
<br class="clear">
<footer>
Documentation generated by <a href="https://github.com/jsdoc/jsdoc">JSDoc 3.6.6</a> on Wed Jun 22 2022 10:04:25 GMT-0500 (Central Daylight Time)
</footer>
<script> prettyPrint(); </script>
<script src="scripts/linenumber.js"> </script>
</body>
</html>

View File

@ -0,0 +1,209 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>JSDoc: Source: core/changecolor.js</title>
<script src="scripts/prettify/prettify.js"> </script>
<script src="scripts/prettify/lang-css.js"> </script>
<!--[if lt IE 9]>
<script src="//html5shiv.googlecode.com/svn/trunk/html5.js"></script>
<![endif]-->
<link type="text/css" rel="stylesheet" href="styles/prettify-tomorrow.css">
<link type="text/css" rel="stylesheet" href="styles/jsdoc-default.css">
</head>
<body>
<div id="main">
<h1 class="page-title">Source: core/changecolor.js</h1>
<section>
<article>
<pre class="prettyprint source linenums"><code>/**
* @author Marzavec ( https://github.com/marzavec )
* @summary Update name color
* @version 1.0.0
* @description Allows calling client to change their nickname color
* @module changecolor
*/
import {
getUserDetails,
} from '../utility/_UAC.js';
/**
* Validate a string as a valid hex color string
* @param {string} color - Color string to validate
* @private
* @todo Move into utility module
* @return {boolean}
*/
const verifyColor = (color) => /(^[0-9A-F]{6}$)|(^[0-9A-F]{3}$)/i.test(color);
/**
* Executes when invoked by a remote client
* @param {Object} env - Enviroment object with references to core, server, socket &amp; payload
* @public
* @return {void}
*/
export async function run({
server, socket, payload,
}) {
const { channel } = socket;
if (server.police.frisk(socket.address, 1)) {
return server.reply({
cmd: 'warn', // @todo Add numeric error code as `id`
text: 'You are changing colors too fast. Wait a moment before trying again.',
channel, // @todo Multichannel
}, socket);
}
// verify user data is string
if (typeof payload.color !== 'string') {
return false;
}
// make sure requested nickname meets standards
const newColor = payload.color.trim().toUpperCase().replace(/#/g, '');
if (newColor !== 'RESET' &amp;&amp; !verifyColor(newColor)) {
return server.reply({
cmd: 'warn',
text: 'Invalid color! Color must be in hex value',
channel, // @todo Multichannel
}, socket);
}
if (newColor === 'RESET') {
socket.color = false; // eslint-disable-line no-param-reassign
} else {
socket.color = newColor; // eslint-disable-line no-param-reassign
}
// build update notice with new color
const updateNotice = {
...getUserDetails(socket),
...{
cmd: 'updateUser',
channel: socket.channel, // @todo Multichannel
},
};
// notify channel that the user has changed their name
// @todo this should be sent to every channel the user is in (multichannel)
server.broadcast(updateNotice, { channel: socket.channel });
return true;
}
/**
* Automatically executes once after server is ready to register this modules hooks
* @param {Object} server - Reference to server enviroment object
* @public
* @return {void}
*/
export function initHooks(server) {
server.registerHook('in', 'chat', this.colorCheck.bind(this), 29);
}
/**
* Executes every time an incoming chat command is invoked
* @param {Object} env - Enviroment object with references to core, server, socket &amp; payload
* @public
* @return {{Object|boolean|string}} Object = same/altered payload,
* false = suppress action,
* string = error
*/
export function colorCheck({
core, server, socket, payload,
}) {
if (typeof payload.text !== 'string') {
return false;
}
if (payload.text.startsWith('/color ')) {
const input = payload.text.split(' ');
// If there is no color target parameter
if (input[1] === undefined) {
server.reply({
cmd: 'warn',
text: 'Refer to `/help changecolor` for instructions on how to use this command.',
channel: socket.channel, // @todo Multichannel
}, socket);
return false;
}
this.run({
core,
server,
socket,
payload: {
cmd: 'changecolor',
color: input[1],
},
});
return false;
}
return payload;
}
/**
* The following payload properties are required to invoke this module:
* "color"
* @public
* @typedef {Array} changecolor/requiredData
*/
export const requiredData = ['color'];
/**
* Module meta information
* @public
* @typedef {Object} changecolor/info
* @property {string} name - Module command name
* @property {string} category - Module category name
* @property {string} description - Information about module
* @property {string} usage - Information about module usage
*/
export const info = {
name: 'changecolor',
category: 'core',
description: 'Allows calling client to change their nickname color',
usage: `
API: { cmd: 'changecolor', color: '&lt;new color as hex>' }
Text: /color &lt;new color as hex>
Removal: /color reset`,
};
</code></pre>
</article>
</section>
</div>
<nav>
<h2><a href="index.html">Home</a></h2><h3>Modules</h3><ul><li><a href="module-addmod.html">addmod</a></li><li><a href="module-ban.html">ban</a></li><li><a href="module-changecolor.html">changecolor</a></li><li><a href="module-changenick.html">changenick</a></li><li><a href="module-chat.html">chat</a></li><li><a href="module-disconnect.html">disconnect</a></li><li><a href="module-dumb.html">dumb</a></li><li><a href="module-emote.html">emote</a></li><li><a href="module-forcecolor.html">forcecolor</a></li><li><a href="module-help.html">help</a></li><li><a href="module-invite.html">invite</a></li><li><a href="module-join.html">join</a></li><li><a href="module-kick.html">kick</a></li><li><a href="module-listusers.html">listusers</a></li><li><a href="module-morestats.html">morestats</a></li><li><a href="module-ping.html">ping</a></li><li><a href="module-reload.html">reload</a></li><li><a href="module-removemod.html">removemod</a></li><li><a href="module-saveconfig.html">saveconfig</a></li><li><a href="module-session.html">session</a></li><li><a href="module-shout.html">shout</a></li><li><a href="module-socketreply.html">socketreply</a></li><li><a href="module-speak.html">speak</a></li><li><a href="module-stats.html">stats</a></li><li><a href="module-unban.html">unban</a></li><li><a href="module-unbanall.html">unbanall</a></li><li><a href="module-whisper.html">whisper</a></li></ul>
</nav>
<br class="clear">
<footer>
Documentation generated by <a href="https://github.com/jsdoc/jsdoc">JSDoc 3.6.6</a> on Wed Jun 22 2022 10:04:25 GMT-0500 (Central Daylight Time)
</footer>
<script> prettyPrint(); </script>
<script src="scripts/linenumber.js"> </script>
</body>
</html>

View File

@ -0,0 +1,264 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>JSDoc: Source: core/changenick.js</title>
<script src="scripts/prettify/prettify.js"> </script>
<script src="scripts/prettify/lang-css.js"> </script>
<!--[if lt IE 9]>
<script src="//html5shiv.googlecode.com/svn/trunk/html5.js"></script>
<![endif]-->
<link type="text/css" rel="stylesheet" href="styles/prettify-tomorrow.css">
<link type="text/css" rel="stylesheet" href="styles/jsdoc-default.css">
</head>
<body>
<div id="main">
<h1 class="page-title">Source: core/changenick.js</h1>
<section>
<article>
<pre class="prettyprint source linenums"><code>/* eslint eqeqeq: 0 */
/**
* @author Marzavec ( https://github.com/marzavec )
* @summary Update nickname
* @version 1.0.0
* @description Allows calling client to change their current nickname
* @module changenick
*/
import {
verifyNickname,
getUserDetails,
} from '../utility/_UAC.js';
/**
* Executes when invoked by a remote client
* @param {Object} env - Enviroment object with references to core, server, socket &amp; payload
* @public
* @return {void}
*/
export async function run({
server, socket, payload,
}) {
const { channel } = socket;
if (server.police.frisk(socket.address, 6)) {
return server.reply({
cmd: 'warn', // @todo Add numeric error code as `id`
text: 'You are changing nicknames too fast. Wait a moment before trying again.',
channel, // @todo Multichannel
}, socket);
}
// verify user data is string
if (typeof payload.nick !== 'string') {
return true;
}
const previousNick = socket.nick;
// make sure requested nickname meets standards
const newNick = payload.nick.trim();
if (!verifyNickname(newNick)) {
return server.reply({
cmd: 'warn', // @todo Add numeric error code as `id`
text: 'Nickname must consist of up to 24 letters, numbers, and underscores',
channel, // @todo Multichannel
}, socket);
}
if (newNick == previousNick) {
return server.reply({
cmd: 'warn', // @todo Add numeric error code as `id`
text: 'You already have that name',
channel, // @todo Multichannel
}, socket);
}
// find any sockets that have the same nickname
const userExists = server.findSockets({
channel,
nick: (targetNick) => targetNick.toLowerCase() === newNick.toLowerCase()
// Allow them to rename themselves to a different case
&amp;&amp; targetNick != previousNick,
});
// return error if found
if (userExists.length > 0) {
// That nickname is already in that channel
return server.reply({
cmd: 'warn', // @todo Add numeric error code as `id`
text: 'Nickname taken',
channel, // @todo Multichannel
}, socket);
}
// build update notice with new nickname
const updateNotice = {
...getUserDetails(socket),
...{
cmd: 'updateUser',
nick: newNick,
channel, // @todo Multichannel
},
};
// build join and leave notices for legacy clients
const leaveNotice = {
cmd: 'onlineRemove',
userid: socket.userid,
nick: socket.nick,
channel, // @todo Multichannel
};
const joinNotice = {
...getUserDetails(socket),
...{
cmd: 'onlineAdd',
nick: newNick,
channel, // @todo Multichannel
},
};
// gather channel peers
const peerList = server.findSockets({ channel });
for (let i = 0, l = peerList.length; i &lt; l; i += 1) {
if (peerList[i].hcProtocol === 1) {
// send join/leave to legacy clients
server.send(leaveNotice, peerList[i]);
server.send(joinNotice, peerList[i]);
} else {
// send update info
// @todo this should be sent to every channel the client is in (multichannel)
server.send(updateNotice, peerList[i]);
}
}
// notify channel that the user has changed their name
server.broadcast({
cmd: 'info',
text: `${socket.nick} is now ${newNick}`,
channel, // @todo Multichannel
}, { channel });
// commit change to nickname
socket.nick = newNick; // eslint-disable-line no-param-reassign
return true;
}
/**
* Automatically executes once after server is ready to register this modules hooks
* @param {Object} server - Reference to server enviroment object
* @public
* @return {void}
*/
export function initHooks(server) {
server.registerHook('in', 'chat', this.nickCheck.bind(this), 29);
}
/**
* Executes every time an incoming chat command is invoked
* @param {Object} env - Enviroment object with references to core, server, socket &amp; payload
* @public
* @return {{Object|boolean|string}} Object = same/altered payload,
* false = suppress action,
* string = error
*/
export function nickCheck({
core, server, socket, payload,
}) {
if (typeof payload.text !== 'string') {
return false;
}
if (payload.text.startsWith('/nick')) {
const input = payload.text.split(' ');
// If there is no nickname target parameter
if (!input[1]) {
server.reply({
cmd: 'warn', // @todo Add numeric error code as `id`
text: 'Refer to `/help nick` for instructions on how to use this command.',
channel: socket.channel, // @todo Multichannel
}, socket);
return false;
}
const newNick = input[1].replace(/@/g, '');
this.run({
core,
server,
socket,
payload: {
cmd: 'changenick',
nick: newNick,
},
});
return false;
}
return payload;
}
/**
* The following payload properties are required to invoke this module:
* "nick"
* @public
* @typedef {Array} changenick/requiredData
*/
export const requiredData = ['nick'];
/**
* Module meta information
* @public
* @typedef {Object} changenick/info
* @property {string} name - Module command name
* @property {string} category - Module category name
* @property {string} description - Information about module
* @property {string} usage - Information about module usage
*/
export const info = {
name: 'changenick',
category: 'core',
description: 'Allows calling client to change their current nickname',
usage: `
API: { cmd: 'changenick', nick: '&lt;new nickname>' }
Text: /nick &lt;new nickname>`,
};
</code></pre>
</article>
</section>
</div>
<nav>
<h2><a href="index.html">Home</a></h2><h3>Modules</h3><ul><li><a href="module-addmod.html">addmod</a></li><li><a href="module-ban.html">ban</a></li><li><a href="module-changecolor.html">changecolor</a></li><li><a href="module-changenick.html">changenick</a></li><li><a href="module-chat.html">chat</a></li><li><a href="module-disconnect.html">disconnect</a></li><li><a href="module-dumb.html">dumb</a></li><li><a href="module-emote.html">emote</a></li><li><a href="module-forcecolor.html">forcecolor</a></li><li><a href="module-help.html">help</a></li><li><a href="module-invite.html">invite</a></li><li><a href="module-join.html">join</a></li><li><a href="module-kick.html">kick</a></li><li><a href="module-listusers.html">listusers</a></li><li><a href="module-morestats.html">morestats</a></li><li><a href="module-ping.html">ping</a></li><li><a href="module-reload.html">reload</a></li><li><a href="module-removemod.html">removemod</a></li><li><a href="module-saveconfig.html">saveconfig</a></li><li><a href="module-session.html">session</a></li><li><a href="module-shout.html">shout</a></li><li><a href="module-socketreply.html">socketreply</a></li><li><a href="module-speak.html">speak</a></li><li><a href="module-stats.html">stats</a></li><li><a href="module-unban.html">unban</a></li><li><a href="module-unbanall.html">unbanall</a></li><li><a href="module-whisper.html">whisper</a></li></ul>
</nav>
<br class="clear">
<footer>
Documentation generated by <a href="https://github.com/jsdoc/jsdoc">JSDoc 3.6.6</a> on Wed Jun 22 2022 10:04:25 GMT-0500 (Central Daylight Time)
</footer>
<script> prettyPrint(); </script>
<script src="scripts/linenumber.js"> </script>
</body>
</html>

View File

@ -0,0 +1,246 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>JSDoc: Source: core/chat.js</title>
<script src="scripts/prettify/prettify.js"> </script>
<script src="scripts/prettify/lang-css.js"> </script>
<!--[if lt IE 9]>
<script src="//html5shiv.googlecode.com/svn/trunk/html5.js"></script>
<![endif]-->
<link type="text/css" rel="stylesheet" href="styles/prettify-tomorrow.css">
<link type="text/css" rel="stylesheet" href="styles/jsdoc-default.css">
</head>
<body>
<div id="main">
<h1 class="page-title">Source: core/chat.js</h1>
<section>
<article>
<pre class="prettyprint source linenums"><code>/**
* @author Marzavec ( https://github.com/marzavec )
* @summary Send chat messages
* @version 1.0.0
* @description Broadcasts passed `text` field to the calling users channel
* @module chat
*/
import {
isAdmin,
isModerator,
} from '../utility/_UAC.js';
/**
* Check and trim string provided by remote client
* @param {string} text - Subject string
* @private
* @todo Move into utility module
* @return {string|boolean}
*/
const parseText = (text) => {
// verifies user input is text
if (typeof text !== 'string') {
return false;
}
let sanitizedText = text;
// strip newlines from beginning and end
sanitizedText = sanitizedText.replace(/^\s*\n|^\s+$|\n\s*$/g, '');
// replace 3+ newlines with just 2 newlines
sanitizedText = sanitizedText.replace(/\n{3,}/g, '\n\n');
return sanitizedText;
};
/**
* Executes when invoked by a remote client
* @param {Object} env - Enviroment object with references to core, server, socket &amp; payload
* @public
* @return {void}
*/
export async function run({
core, server, socket, payload,
}) {
// check user input
const text = parseText(payload.text);
if (!text) {
// lets not send objects or empty text, yea?
return server.police.frisk(socket.address, 13);
}
// check for spam
const score = text.length / 83 / 4;
if (server.police.frisk(socket.address, score)) {
return server.reply({
cmd: 'warn', // @todo Add numeric error code as `id`
text: 'You are sending too much text. Wait a moment and try again.\nPress the up arrow key to restore your last message.',
channel: socket.channel, // @todo Multichannel
}, socket);
}
// build chat payload
const outgoingPayload = {
cmd: 'chat',
nick: socket.nick, /* @legacy */
uType: socket.uType, /* @legacy */
userid: socket.userid,
channel: socket.channel,
text,
level: socket.level,
};
if (isAdmin(socket.level)) {
outgoingPayload.admin = true;
} else if (isModerator(socket.level)) {
outgoingPayload.mod = true;
}
if (socket.trip) {
outgoingPayload.trip = socket.trip; /* @legacy */
}
if (socket.color) {
outgoingPayload.color = socket.color;
}
// broadcast to channel peers
server.broadcast(outgoingPayload, { channel: socket.channel });
// stats are fun
core.stats.increment('messages-sent');
return true;
}
/**
* Automatically executes once after server is ready to register this modules hooks
* @param {Object} server - Reference to server enviroment object
* @public
* @return {void}
*/
export function initHooks(server) {
server.registerHook('in', 'chat', this.commandCheckIn.bind(this), 20);
server.registerHook('in', 'chat', this.finalCmdCheck.bind(this), 254);
}
/**
* Executes every time an incoming chat command is invoked;
* checks for miscellaneous '/' based commands
* @param {Object} env - Enviroment object with references to core, server, socket &amp; payload
* @public
* @return {{Object|boolean|string}} Object = same/altered payload,
* false = suppress action,
* string = error
*/
export function commandCheckIn({ server, socket, payload }) {
if (typeof payload.text !== 'string') {
return false;
}
if (payload.text.startsWith('/myhash')) {
server.reply({
cmd: 'info',
text: `Your hash: ${socket.hash}`,
channel: socket.channel, // @todo Multichannel
}, socket);
return false;
}
return payload;
}
/**
* Executes every time an incoming chat command is invoked;
* assumes a failed chat command invocation and will reject with notice
* @param {Object} env - Enviroment object with references to core, server, socket &amp; payload
* @public
* @return {{Object|boolean|string}} Object = same/altered payload,
* false = suppress action,
* string = error
*/
export function finalCmdCheck({ server, socket, payload }) {
if (typeof payload.text !== 'string') {
return false;
}
if (!payload.text.startsWith('/')) {
return payload;
}
if (payload.text.startsWith('//')) {
payload.text = payload.text.substr(1); // eslint-disable-line no-param-reassign
return payload;
}
server.reply({
cmd: 'warn', // @todo Add numeric error code as `id`
text: `Unknown command: ${payload.text}`,
channel: socket.channel, // @todo Multichannel
}, socket);
return false;
}
/**
* The following payload properties are required to invoke this module:
* "text"
* @public
* @typedef {Array} chat/requiredData
*/
export const requiredData = ['text'];
/**
* Module meta information
* @public
* @typedef {Object} chat/info
* @property {string} name - Module command name
* @property {string} category - Module category name
* @property {string} description - Information about module
* @property {string} usage - Information about module usage
*/
export const info = {
name: 'chat',
category: 'core',
description: 'Broadcasts passed `text` field to the calling users channel',
usage: `
API: { cmd: 'chat', text: '&lt;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`,
};
</code></pre>
</article>
</section>
</div>
<nav>
<h2><a href="index.html">Home</a></h2><h3>Modules</h3><ul><li><a href="module-addmod.html">addmod</a></li><li><a href="module-ban.html">ban</a></li><li><a href="module-changecolor.html">changecolor</a></li><li><a href="module-changenick.html">changenick</a></li><li><a href="module-chat.html">chat</a></li><li><a href="module-disconnect.html">disconnect</a></li><li><a href="module-dumb.html">dumb</a></li><li><a href="module-emote.html">emote</a></li><li><a href="module-forcecolor.html">forcecolor</a></li><li><a href="module-help.html">help</a></li><li><a href="module-invite.html">invite</a></li><li><a href="module-join.html">join</a></li><li><a href="module-kick.html">kick</a></li><li><a href="module-listusers.html">listusers</a></li><li><a href="module-morestats.html">morestats</a></li><li><a href="module-ping.html">ping</a></li><li><a href="module-reload.html">reload</a></li><li><a href="module-removemod.html">removemod</a></li><li><a href="module-saveconfig.html">saveconfig</a></li><li><a href="module-session.html">session</a></li><li><a href="module-shout.html">shout</a></li><li><a href="module-socketreply.html">socketreply</a></li><li><a href="module-speak.html">speak</a></li><li><a href="module-stats.html">stats</a></li><li><a href="module-unban.html">unban</a></li><li><a href="module-unbanall.html">unbanall</a></li><li><a href="module-whisper.html">whisper</a></li></ul>
</nav>
<br class="clear">
<footer>
Documentation generated by <a href="https://github.com/jsdoc/jsdoc">JSDoc 3.6.6</a> on Wed Jun 22 2022 10:04:25 GMT-0500 (Central Daylight Time)
</footer>
<script> prettyPrint(); </script>
<script src="scripts/linenumber.js"> </script>
</body>
</html>

View File

@ -0,0 +1,213 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>JSDoc: Source: core/emote.js</title>
<script src="scripts/prettify/prettify.js"> </script>
<script src="scripts/prettify/lang-css.js"> </script>
<!--[if lt IE 9]>
<script src="//html5shiv.googlecode.com/svn/trunk/html5.js"></script>
<![endif]-->
<link type="text/css" rel="stylesheet" href="styles/prettify-tomorrow.css">
<link type="text/css" rel="stylesheet" href="styles/jsdoc-default.css">
</head>
<body>
<div id="main">
<h1 class="page-title">Source: core/emote.js</h1>
<section>
<article>
<pre class="prettyprint source linenums"><code>/**
* @author Marzavec ( https://github.com/marzavec )
* @summary Emote / action text
* @version 1.0.0
* @description Broadcasts an emote to the current channel
* @module emote
*/
/**
* Check and trim string provided by remote client
* @param {string} text - Subject string
* @private
* @todo Move into utility module
* @return {string|boolean}
*/
const parseText = (text) => {
// verifies user input is text
if (typeof text !== 'string') {
return false;
}
let sanitizedText = text;
// strip newlines from beginning and end
sanitizedText = sanitizedText.replace(/^\s*\n|^\s+$|\n\s*$/g, '');
// replace 3+ newlines with just 2 newlines
sanitizedText = sanitizedText.replace(/\n{3,}/g, '\n\n');
return sanitizedText;
};
/**
* Executes when invoked by a remote client
* @param {Object} env - Enviroment object with references to core, server, socket &amp; payload
* @public
* @return {void}
*/
export async function run({ server, socket, payload }) {
// check user input
let text = parseText(payload.text);
if (!text) {
// lets not send objects or empty text, yea?
return server.police.frisk(socket.address, 8);
}
// check for spam
const score = text.length / 83 / 4;
if (server.police.frisk(socket.address, score)) {
return server.reply({
cmd: 'warn', // @todo Add numeric error code as `id`
text: 'You are sending too much text. Wait a moment and try again.\nPress the up arrow key to restore your last message.',
channel: socket.channel, // @todo Multichannel
}, socket);
}
if (!text.startsWith("'")) {
text = ` ${text}`;
}
const newPayload = {
cmd: 'emote',
nick: socket.nick,
userid: socket.userid,
text: `@${socket.nick}${text}`,
channel: socket.channel, // @todo Multichannel
};
if (socket.trip) {
newPayload.trip = socket.trip;
}
// broadcast to channel peers
server.broadcast(newPayload, { channel: socket.channel });
return true;
}
/**
* Automatically executes once after server is ready to register this modules hooks
* @param {Object} server - Reference to server enviroment object
* @public
* @return {void}
*/
export function initHooks(server) {
server.registerHook('in', 'chat', this.emoteCheck.bind(this), 30);
}
/**
* Executes every time an incoming chat command is invoked;
* hooks chat commands checking for /me
* @param {Object} env - Enviroment object with references to core, server, socket &amp; payload
* @public
* @return {{Object|boolean|string}} Object = same/altered payload,
* false = suppress action,
* string = error
*/
export function emoteCheck({
core, server, socket, payload,
}) {
if (typeof payload.text !== 'string') {
return false;
}
if (payload.text.startsWith('/me ')) {
const input = payload.text.split(' ');
// If there is no emote target parameter
if (input[1] === undefined) {
server.reply({
cmd: 'warn', // @todo Add numeric error code as `id`
text: 'Refer to `/help emote` for instructions on how to use this command.',
channel: socket.channel, // @todo Multichannel
}, socket);
return false;
}
input.splice(0, 1);
const actionText = input.join(' ');
this.run({
core,
server,
socket,
payload: {
cmd: 'emote',
text: actionText,
},
});
return false;
}
return payload;
}
/**
* The following payload properties are required to invoke this module:
* "text"
* @public
* @typedef {Array} emote/requiredData
*/
export const requiredData = ['text'];
/**
* Module meta information
* @public
* @typedef {Object} emote/info
* @property {string} name - Module command name
* @property {string} category - Module category name
* @property {string} description - Information about module
* @property {string} usage - Information about module usage
*/
export const info = {
name: 'emote',
category: 'core',
description: 'Broadcasts an emote to the current channel',
usage: `
API: { cmd: 'emote', text: '&lt;emote/action text>' }
Text: /me &lt;emote/action text>`,
};
</code></pre>
</article>
</section>
</div>
<nav>
<h2><a href="index.html">Home</a></h2><h3>Modules</h3><ul><li><a href="module-addmod.html">addmod</a></li><li><a href="module-ban.html">ban</a></li><li><a href="module-changecolor.html">changecolor</a></li><li><a href="module-changenick.html">changenick</a></li><li><a href="module-chat.html">chat</a></li><li><a href="module-disconnect.html">disconnect</a></li><li><a href="module-dumb.html">dumb</a></li><li><a href="module-emote.html">emote</a></li><li><a href="module-forcecolor.html">forcecolor</a></li><li><a href="module-help.html">help</a></li><li><a href="module-invite.html">invite</a></li><li><a href="module-join.html">join</a></li><li><a href="module-kick.html">kick</a></li><li><a href="module-listusers.html">listusers</a></li><li><a href="module-morestats.html">morestats</a></li><li><a href="module-ping.html">ping</a></li><li><a href="module-reload.html">reload</a></li><li><a href="module-removemod.html">removemod</a></li><li><a href="module-saveconfig.html">saveconfig</a></li><li><a href="module-session.html">session</a></li><li><a href="module-shout.html">shout</a></li><li><a href="module-socketreply.html">socketreply</a></li><li><a href="module-speak.html">speak</a></li><li><a href="module-stats.html">stats</a></li><li><a href="module-unban.html">unban</a></li><li><a href="module-unbanall.html">unbanall</a></li><li><a href="module-whisper.html">whisper</a></li></ul>
</nav>
<br class="clear">
<footer>
Documentation generated by <a href="https://github.com/jsdoc/jsdoc">JSDoc 3.6.6</a> on Wed Jun 22 2022 10:04:25 GMT-0500 (Central Daylight Time)
</footer>
<script> prettyPrint(); </script>
<script src="scripts/linenumber.js"> </script>
</body>
</html>

View File

@ -0,0 +1,185 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>JSDoc: Source: core/help.js</title>
<script src="scripts/prettify/prettify.js"> </script>
<script src="scripts/prettify/lang-css.js"> </script>
<!--[if lt IE 9]>
<script src="//html5shiv.googlecode.com/svn/trunk/html5.js"></script>
<![endif]-->
<link type="text/css" rel="stylesheet" href="styles/prettify-tomorrow.css">
<link type="text/css" rel="stylesheet" href="styles/jsdoc-default.css">
</head>
<body>
<div id="main">
<h1 class="page-title">Source: core/help.js</h1>
<section>
<article>
<pre class="prettyprint source linenums"><code>/**
* @author Marzavec ( https://github.com/marzavec )
* @summary Get help
* @version 1.0.0
* @description Outputs information about the servers current protocol
* @module help
*/
/**
* Executes when invoked by a remote client
* @param {Object} env - Enviroment object with references to core, server, socket &amp; payload
* @public
* @return {void}
*/
export async function run({
core, server, socket, payload,
}) {
// check for spam
if (server.police.frisk(socket.address, 2)) {
return server.reply({
cmd: 'warn', // @todo Add numeric error code as `id`
text: 'You are sending too much text. Wait a moment and try again.\nPress the up arrow key to restore your last message.',
channel: socket.channel, // @todo Multichannel
}, socket);
}
// verify user input
if (typeof payload.command !== 'undefined' &amp;&amp; typeof payload.command !== 'string') {
return true;
}
let reply = '';
if (typeof payload.command === 'undefined') {
reply += '# All commands:\n|Category:|Name:|\n|---:|---|\n';
const categories = core.commands.categoriesList.sort();
for (let i = 0, j = categories.length; i &lt; 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),
);
reply += `${catCommands.map((c) => `${c.info.name}`).join(', ')}|\n`;
}
reply += '---\nFor specific help on certain commands, use either:\nText: `/help &lt;command name>`\nAPI: `{cmd: \'help\', command: \'&lt;command name>\'}`';
} else {
const command = core.commands.get(payload.command);
if (typeof command === 'undefined') {
reply += 'Unknown command';
} else {
reply += `# ${command.info.name} command:\n| | |\n|---:|---|\n`;
reply += `|**Name:**|${command.info.name}|\n`;
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}`;
}
}
// output reply
server.reply({
cmd: 'info',
text: reply,
channel: socket.channel, // @todo Multichannel
}, socket);
return true;
}
/**
* Automatically executes once after server is ready to register this modules hooks
* @param {Object} server - Reference to server enviroment object
* @public
* @return {void}
*/
export function initHooks(server) {
server.registerHook('in', 'chat', this.helpCheck.bind(this), 28);
}
/**
* Executes every time an incoming chat command is invoked;
* hooks chat commands checking for /help
* @param {Object} env - Enviroment object with references to core, server, socket &amp; payload
* @public
* @return {{Object|boolean|string}} Object = same/altered payload,
* false = suppress action,
* string = error
*/
export function helpCheck({
core, server, socket, payload,
}) {
if (typeof payload.text !== 'string') {
return false;
}
if (payload.text.startsWith('/help')) {
const input = payload.text.substr(1).split(' ', 2);
this.run({
core,
server,
socket,
payload: {
cmd: input[0],
command: input[1],
},
});
return false;
}
return payload;
}
/**
* Module meta information
* @public
* @typedef {Object} help/info
* @property {string} name - Module command name
* @property {string} category - Module category name
* @property {string} description - Information about module
* @property {string} usage - Information about module usage
*/
export const info = {
name: 'help',
category: 'core',
description: 'Outputs information about the servers current protocol',
usage: `
API: { cmd: 'help', command: '&lt;optional command name>' }
Text: /help &lt;optional command name>`,
};
</code></pre>
</article>
</section>
</div>
<nav>
<h2><a href="index.html">Home</a></h2><h3>Modules</h3><ul><li><a href="module-addmod.html">addmod</a></li><li><a href="module-ban.html">ban</a></li><li><a href="module-changecolor.html">changecolor</a></li><li><a href="module-changenick.html">changenick</a></li><li><a href="module-chat.html">chat</a></li><li><a href="module-disconnect.html">disconnect</a></li><li><a href="module-dumb.html">dumb</a></li><li><a href="module-emote.html">emote</a></li><li><a href="module-forcecolor.html">forcecolor</a></li><li><a href="module-help.html">help</a></li><li><a href="module-invite.html">invite</a></li><li><a href="module-join.html">join</a></li><li><a href="module-kick.html">kick</a></li><li><a href="module-listusers.html">listusers</a></li><li><a href="module-morestats.html">morestats</a></li><li><a href="module-ping.html">ping</a></li><li><a href="module-reload.html">reload</a></li><li><a href="module-removemod.html">removemod</a></li><li><a href="module-saveconfig.html">saveconfig</a></li><li><a href="module-session.html">session</a></li><li><a href="module-shout.html">shout</a></li><li><a href="module-socketreply.html">socketreply</a></li><li><a href="module-speak.html">speak</a></li><li><a href="module-stats.html">stats</a></li><li><a href="module-unban.html">unban</a></li><li><a href="module-unbanall.html">unbanall</a></li><li><a href="module-whisper.html">whisper</a></li></ul>
</nav>
<br class="clear">
<footer>
Documentation generated by <a href="https://github.com/jsdoc/jsdoc">JSDoc 3.6.6</a> on Wed Jun 22 2022 10:04:25 GMT-0500 (Central Daylight Time)
</footer>
<script> prettyPrint(); </script>
<script src="scripts/linenumber.js"> </script>
</body>
</html>

View File

@ -0,0 +1,174 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>JSDoc: Source: core/invite.js</title>
<script src="scripts/prettify/prettify.js"> </script>
<script src="scripts/prettify/lang-css.js"> </script>
<!--[if lt IE 9]>
<script src="//html5shiv.googlecode.com/svn/trunk/html5.js"></script>
<![endif]-->
<link type="text/css" rel="stylesheet" href="styles/prettify-tomorrow.css">
<link type="text/css" rel="stylesheet" href="styles/jsdoc-default.css">
</head>
<body>
<div id="main">
<h1 class="page-title">Source: core/invite.js</h1>
<section>
<article>
<pre class="prettyprint source linenums"><code>/**
* @author Marzavec ( https://github.com/marzavec )
* @summary Send an invite
* @version 1.0.0
* @description Sends an invite to the target client with the provided channel, or a random channel
* @module invite
*/
import {
findUser,
} from '../utility/_Channels.js';
import {
Errors,
} from '../utility/_Constants.js';
import {
legacyInviteOut,
legacyInviteReply,
} from '../utility/_LegacyFunctions.js';
/**
* Returns the channel that should be invited to.
* @param {any} channel
* @private
* @return {string}
*/
export function getChannel(channel = undefined) {
if (typeof channel === 'string') {
return channel;
}
return Math.random().toString(36).substr(2, 8);
}
/**
* Executes when invoked by a remote client
* @param {Object} env - Enviroment object with references to core, server, socket &amp; payload
* @public
* @return {void}
*/
export async function run({
core, server, socket, payload,
}) {
// check for spam
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.',
id: Errors.Invite.RATELIMIT,
channel: socket.channel, // @todo Multichannel
}, socket);
}
// verify user input
// if this is a legacy client add missing params to payload
if (socket.hcProtocol === 1) {
if (typeof socket.channel === 'undefined' || typeof payload.nick !== 'string') {
return true;
}
payload.channel = socket.channel; // eslint-disable-line no-param-reassign
} else if (typeof payload.userid !== 'number' || typeof payload.channel !== 'string') {
return true;
}
// @todo Verify this socket is part of payload.channel - multichannel patch
// find target user
const targetUser = findUser(server, payload);
if (!targetUser) {
return server.reply({
cmd: 'warn',
text: 'Could not find user in that channel',
id: Errors.Global.UNKNOWN_USER,
channel: socket.channel, // @todo Multichannel
}, socket);
}
// generate common channel
const channel = getChannel(payload.to);
// build invite
const outgoingPayload = {
cmd: 'invite',
channel: socket.channel, // @todo Multichannel
from: socket.userid,
to: targetUser.userid,
inviteChannel: channel,
};
// send invite notice to target client
if (targetUser.hcProtocol === 1) {
server.reply(legacyInviteOut(outgoingPayload, socket.nick), targetUser);
} else {
server.reply(outgoingPayload, targetUser);
}
// send invite notice to this client
if (socket.hcProtocol === 1) {
server.reply(legacyInviteReply(outgoingPayload, targetUser.nick), socket);
} else {
server.reply(outgoingPayload, socket);
}
// stats are fun
core.stats.increment('invites-sent');
return true;
}
/**
* Module meta information
* @public
* @typedef {Object} invite/info
* @property {string} name - Module command name
* @property {string} category - Module category name
* @property {string} description - Information about module
* @property {string} usage - Information about module usage
*/
export const info = {
name: 'invite',
category: 'core',
description: 'Sends an invite to the target client with the provided channel, or a random channel.',
usage: `
API: { cmd: 'invite', nick: '&lt;target nickname>', to: '&lt;optional destination channel>' }`,
};
</code></pre>
</article>
</section>
</div>
<nav>
<h2><a href="index.html">Home</a></h2><h3>Modules</h3><ul><li><a href="module-addmod.html">addmod</a></li><li><a href="module-ban.html">ban</a></li><li><a href="module-changecolor.html">changecolor</a></li><li><a href="module-changenick.html">changenick</a></li><li><a href="module-chat.html">chat</a></li><li><a href="module-disconnect.html">disconnect</a></li><li><a href="module-dumb.html">dumb</a></li><li><a href="module-emote.html">emote</a></li><li><a href="module-forcecolor.html">forcecolor</a></li><li><a href="module-help.html">help</a></li><li><a href="module-invite.html">invite</a></li><li><a href="module-join.html">join</a></li><li><a href="module-kick.html">kick</a></li><li><a href="module-listusers.html">listusers</a></li><li><a href="module-morestats.html">morestats</a></li><li><a href="module-ping.html">ping</a></li><li><a href="module-reload.html">reload</a></li><li><a href="module-removemod.html">removemod</a></li><li><a href="module-saveconfig.html">saveconfig</a></li><li><a href="module-session.html">session</a></li><li><a href="module-shout.html">shout</a></li><li><a href="module-socketreply.html">socketreply</a></li><li><a href="module-speak.html">speak</a></li><li><a href="module-stats.html">stats</a></li><li><a href="module-unban.html">unban</a></li><li><a href="module-unbanall.html">unbanall</a></li><li><a href="module-whisper.html">whisper</a></li></ul>
</nav>
<br class="clear">
<footer>
Documentation generated by <a href="https://github.com/jsdoc/jsdoc">JSDoc 3.6.6</a> on Wed Jun 22 2022 10:04:25 GMT-0500 (Central Daylight Time)
</footer>
<script> prettyPrint(); </script>
<script src="scripts/linenumber.js"> </script>
</body>
</html>

View File

@ -0,0 +1,323 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>JSDoc: Source: core/join.js</title>
<script src="scripts/prettify/prettify.js"> </script>
<script src="scripts/prettify/lang-css.js"> </script>
<!--[if lt IE 9]>
<script src="//html5shiv.googlecode.com/svn/trunk/html5.js"></script>
<![endif]-->
<link type="text/css" rel="stylesheet" href="styles/prettify-tomorrow.css">
<link type="text/css" rel="stylesheet" href="styles/jsdoc-default.css">
</head>
<body>
<div id="main">
<h1 class="page-title">Source: core/join.js</h1>
<section>
<article>
<pre class="prettyprint source linenums"><code>/* eslint no-param-reassign: 0 */
/* eslint import/no-cycle: [0, { ignoreExternal: true }] */
/**
* @author Marzavec ( https://github.com/marzavec )
* @summary Join target channel
* @version 1.0.0
* @description Join the target channel using the supplied nick and password
* @module join
*/
import {
getSession,
} from './session.js';
import {
canJoinChannel,
socketInChannel,
} from '../utility/_Channels.js';
import {
Errors,
} from '../utility/_Constants.js';
import {
upgradeLegacyJoin,
legacyLevelToLabel,
} from '../utility/_LegacyFunctions.js';
import {
verifyNickname,
getUserPerms,
getUserDetails,
} from '../utility/_UAC.js';
/**
* Executes when invoked by a remote client
* @param {Object} env - Enviroment object with references to core, server, socket &amp; payload
* @public
* @return {void}
*/
export async function run({
core, server, socket, payload,
}) {
// check for spam
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.',
id: Errors.Join.RATELIMIT,
channel: false, // @todo Multichannel, false for global event
}, socket);
}
// `join` is the legacy entry point, check if it needs to be upgraded
if (typeof socket.hcProtocol === 'undefined') {
payload = upgradeLegacyJoin(server, socket, payload);
}
// store payload values
const { channel, nick, pass } = payload;
// check if a client is able to join target channel
const mayJoin = canJoinChannel(channel, socket);
if (mayJoin !== true) {
return server.reply({
cmd: 'warn',
text: 'You may not join that channel.',
id: mayJoin,
channel: false, // @todo Multichannel, false for global event
}, socket);
}
// calling socket already in a channel
// @todo multichannel update, will remove
if (typeof socket.channel !== 'undefined') {
return server.reply({
cmd: 'warn', // @todo Remove this
text: 'Joining more than one channel is not currently supported',
id: Errors.Join.ALREADY_JOINED,
channel: false, // @todo Multichannel, false for global event
}, socket);
}
// end todo
// validates the user input for `nick`
if (verifyNickname(nick, socket) !== true) {
return server.reply({
cmd: 'warn',
text: 'Nickname must consist of up to 24 letters, numbers, and underscores',
id: Errors.Join.INVALID_NICK,
channel: false, // @todo Multichannel, false for global event
}, socket);
}
// get trip and level
const { trip, level } = getUserPerms(pass, core.saltKey, core.appConfig.data, channel);
// store the user values
const userInfo = {
nick,
trip,
uType: legacyLevelToLabel(level),
hash: socket.hash,
level,
userid: socket.userid,
isBot: socket.isBot,
color: socket.color,
channel,
};
// check if the nickname already exists in the channel
const userExists = server.findSockets({
channel,
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',
id: Errors.Join.NAME_TAKEN,
channel: false, // @todo Multichannel, false for global event
}, socket);
}
// prepare to notify channel peers
const newPeerList = server.findSockets({ channel });
const nicks = []; /* @legacy */
const users = [];
const joinAnnouncement = { ...{ cmd: 'onlineAdd' }, ...userInfo };
// send join announcement and prep online set reply
for (let i = 0, l = newPeerList.length; i &lt; l; i += 1) {
server.reply(joinAnnouncement, newPeerList[i]);
nicks.push(newPeerList[i].nick); /* @legacy */
users.push({
...{
channel,
isme: false,
},
...getUserDetails(newPeerList[i]),
});
}
// store user info
socket.nick = userInfo.nick;
socket.trip = userInfo.trip;
socket.level = userInfo.level;
socket.uType = userInfo.uType; /* @legacy */
socket.channel = channel; /* @legacy */
// @todo multi-channel patch
// socket.channels.push(channel);
socket.channels = [channel];
nicks.push(userInfo.nick); /* @legacy */
users.push({ ...{ isme: true, isBot: socket.isBot }, ...userInfo });
// reply with channel peer list
server.reply({
cmd: 'onlineSet',
nicks, /* @legacy */
users,
channel, // @todo Multichannel (?)
}, socket);
// update client with new session info
server.reply({
cmd: 'session',
restored: false,
token: getSession(socket, core),
channels: socket.channels,
}, socket);
// stats are fun
core.stats.increment('users-joined');
return true;
}
export function restoreJoin({
server, socket, channel,
}) {
// check if a client is able to join target channel
const mayJoin = canJoinChannel(channel, socket);
if (mayJoin !== true) {
return server.reply({
cmd: 'warn',
text: 'You may not join that channel.',
id: mayJoin,
channel: false, // @todo Multichannel, false for global event
}, socket);
}
// store the user values
const userInfo = {
nick: socket.nick,
trip: socket.trip,
uType: legacyLevelToLabel(socket.level),
hash: socket.hash,
level: socket.level,
userid: socket.userid,
isBot: socket.isBot,
color: socket.color,
channel,
};
// prepare to notify channel peers
const newPeerList = server.findSockets({ channel });
const nicks = []; /* @legacy */
const users = [];
const joinAnnouncement = { ...{ cmd: 'onlineAdd' }, ...userInfo };
// build update notice with new privileges
const updateAnnouncement = {
...getUserDetails(socket),
...{
cmd: 'updateUser',
online: true,
},
};
const isDuplicate = socketInChannel(server, channel, socket);
// send join announcement and prep online set reply
for (let i = 0, l = newPeerList.length; i &lt; l; i += 1) {
if (isDuplicate) {
server.reply(updateAnnouncement, newPeerList[i]);
} else {
server.reply(joinAnnouncement, newPeerList[i]);
}
nicks.push(newPeerList[i].nick); /* @legacy */
users.push({
...{
channel,
isme: false,
},
...getUserDetails(newPeerList[i]),
});
}
nicks.push(userInfo.nick); /* @legacy */
users.push({ ...{ isme: true, isBot: socket.isBot }, ...userInfo });
// reply with channel peer list
server.reply({
cmd: 'onlineSet',
nicks, /* @legacy */
users,
channel, // @todo Multichannel (?)
}, socket);
socket.channel = channel; /* @legacy */
socket.channels.push(channel);
return true;
}
/**
* Module meta information
* @public
* @typedef {Object} join/info
* @property {string} name - Module command name
* @property {string} category - Module category name
* @property {string} description - Information about module
* @property {string} usage - Information about module usage
*/
export const info = {
name: 'join',
category: 'core',
description: 'Join the target channel using the supplied nick and password',
usage: `
API: { cmd: 'join', nick: '&lt;your nickname>', pass: '&lt;optional password>', channel: '&lt;target channel>' }`,
};
</code></pre>
</article>
</section>
</div>
<nav>
<h2><a href="index.html">Home</a></h2><h3>Modules</h3><ul><li><a href="module-addmod.html">addmod</a></li><li><a href="module-ban.html">ban</a></li><li><a href="module-changecolor.html">changecolor</a></li><li><a href="module-changenick.html">changenick</a></li><li><a href="module-chat.html">chat</a></li><li><a href="module-disconnect.html">disconnect</a></li><li><a href="module-dumb.html">dumb</a></li><li><a href="module-emote.html">emote</a></li><li><a href="module-forcecolor.html">forcecolor</a></li><li><a href="module-help.html">help</a></li><li><a href="module-invite.html">invite</a></li><li><a href="module-join.html">join</a></li><li><a href="module-kick.html">kick</a></li><li><a href="module-listusers.html">listusers</a></li><li><a href="module-morestats.html">morestats</a></li><li><a href="module-ping.html">ping</a></li><li><a href="module-reload.html">reload</a></li><li><a href="module-removemod.html">removemod</a></li><li><a href="module-saveconfig.html">saveconfig</a></li><li><a href="module-session.html">session</a></li><li><a href="module-shout.html">shout</a></li><li><a href="module-socketreply.html">socketreply</a></li><li><a href="module-speak.html">speak</a></li><li><a href="module-stats.html">stats</a></li><li><a href="module-unban.html">unban</a></li><li><a href="module-unbanall.html">unbanall</a></li><li><a href="module-whisper.html">whisper</a></li></ul>
</nav>
<br class="clear">
<footer>
Documentation generated by <a href="https://github.com/jsdoc/jsdoc">JSDoc 3.6.6</a> on Wed Jun 22 2022 10:04:25 GMT-0500 (Central Daylight Time)
</footer>
<script> prettyPrint(); </script>
<script src="scripts/linenumber.js"> </script>
</body>
</html>

View File

@ -0,0 +1,215 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>JSDoc: Source: core/morestats.js</title>
<script src="scripts/prettify/prettify.js"> </script>
<script src="scripts/prettify/lang-css.js"> </script>
<!--[if lt IE 9]>
<script src="//html5shiv.googlecode.com/svn/trunk/html5.js"></script>
<![endif]-->
<link type="text/css" rel="stylesheet" href="styles/prettify-tomorrow.css">
<link type="text/css" rel="stylesheet" href="styles/jsdoc-default.css">
</head>
<body>
<div id="main">
<h1 class="page-title">Source: core/morestats.js</h1>
<section>
<article>
<pre class="prettyprint source linenums"><code>/**
* @author Marzavec ( https://github.com/marzavec )
* @summary Get stats
* @version 1.0.0
* @description Sends back current server stats to the calling client
* @module morestats
*/
/**
* Format input time into string
* @param {Date} time - Subject date
* @private
* @return {string}
*/
const formatTime = (time) => {
let seconds = time[0] + time[1] / 1e9;
let minutes = Math.floor(seconds / 60);
seconds %= 60;
let hours = Math.floor(minutes / 60);
minutes %= 60;
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`;
};
/**
* Executes when invoked by a remote client
* @param {Object} env - Enviroment object with references to core, server, socket &amp; payload
* @public
* @return {void}
*/
export async function run({ core, server, socket }) {
// gather connection and channel count
const ips = {};
const channels = {};
// @todo use public channel flag
const publicChanCounts = {
lounge: 0,
meta: 0,
math: 0,
physics: 0,
chemistry: 0,
technology: 0,
programming: 0,
games: 0,
banana: 0,
chinese: 0,
};
// @todo code resuage between here and `session`; should share exported 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] += 1;
}
}
});
const uniqueClientCount = Object.keys(ips).length;
const uniqueChannels = Object.keys(channels).length;
const joins = core.stats.get('users-joined') || 0;
const invites = core.stats.get('invites-sent') || 0;
const messages = core.stats.get('messages-sent') || 0;
const banned = core.stats.get('users-banned') || 0;
const kicked = core.stats.get('users-kicked') || 0;
const stats = core.stats.get('stats-requested') || 0;
const uptime = formatTime(process.hrtime(core.stats.get('start-time')));
// dispatch info
server.reply({
cmd: 'info',
users: uniqueClientCount,
chans: uniqueChannels,
joins,
invites,
messages,
banned,
kicked,
stats,
uptime,
public: publicChanCounts,
text: `current-connections: ${uniqueClientCount}
current-channels: ${uniqueChannels}
users-joined: ${joins}
invites-sent: ${invites}
messages-sent: ${messages}
users-banned: ${banned}
users-kicked: ${kicked}
stats-requested: ${stats}
server-uptime: ${uptime}`,
channel: socket.channel, // @todo Multichannel
}, socket);
// stats are fun
core.stats.increment('stats-requested');
return true;
}
/**
* Automatically executes once after server is ready to register this modules hooks
* @param {Object} server - Reference to server enviroment object
* @public
* @return {void}
*/
export function initHooks(server) {
server.registerHook('in', 'chat', this.statsCheck.bind(this), 26);
}
/**
* Executes every time an incoming chat command is invoked;
* hooks chat commands checking for /stats
* @param {Object} env - Enviroment object with references to core, server, socket &amp; payload
* @public
* @return {{Object|boolean|string}} Object = same/altered payload,
* false = suppress action,
* string = error
*/
export function statsCheck({
core, server, socket, payload,
}) {
if (typeof payload.text !== 'string') {
return false;
}
if (payload.text.startsWith('/stats')) {
this.run({
core,
server,
socket,
payload: {
cmd: 'morestats',
},
});
return false;
}
return payload;
}
/**
* Module meta information
* @public
* @typedef {Object} morestats/info
* @property {string} name - Module command name
* @property {string} category - Module category name
* @property {string} description - Information about module
* @property {string} usage - Information about module usage
*/
export const info = {
name: 'morestats',
category: 'core',
description: 'Sends back current server stats to the calling client',
usage: `
API: { cmd: 'morestats' }
Text: /stats`,
};
</code></pre>
</article>
</section>
</div>
<nav>
<h2><a href="index.html">Home</a></h2><h3>Modules</h3><ul><li><a href="module-addmod.html">addmod</a></li><li><a href="module-ban.html">ban</a></li><li><a href="module-changecolor.html">changecolor</a></li><li><a href="module-changenick.html">changenick</a></li><li><a href="module-chat.html">chat</a></li><li><a href="module-disconnect.html">disconnect</a></li><li><a href="module-dumb.html">dumb</a></li><li><a href="module-emote.html">emote</a></li><li><a href="module-forcecolor.html">forcecolor</a></li><li><a href="module-help.html">help</a></li><li><a href="module-invite.html">invite</a></li><li><a href="module-join.html">join</a></li><li><a href="module-kick.html">kick</a></li><li><a href="module-listusers.html">listusers</a></li><li><a href="module-morestats.html">morestats</a></li><li><a href="module-ping.html">ping</a></li><li><a href="module-reload.html">reload</a></li><li><a href="module-removemod.html">removemod</a></li><li><a href="module-saveconfig.html">saveconfig</a></li><li><a href="module-session.html">session</a></li><li><a href="module-shout.html">shout</a></li><li><a href="module-socketreply.html">socketreply</a></li><li><a href="module-speak.html">speak</a></li><li><a href="module-stats.html">stats</a></li><li><a href="module-unban.html">unban</a></li><li><a href="module-unbanall.html">unbanall</a></li><li><a href="module-whisper.html">whisper</a></li></ul>
</nav>
<br class="clear">
<footer>
Documentation generated by <a href="https://github.com/jsdoc/jsdoc">JSDoc 3.6.6</a> on Wed Jun 22 2022 10:04:25 GMT-0500 (Central Daylight Time)
</footer>
<script> prettyPrint(); </script>
<script src="scripts/linenumber.js"> </script>
</body>
</html>

View File

@ -0,0 +1,83 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>JSDoc: Source: core/ping.js</title>
<script src="scripts/prettify/prettify.js"> </script>
<script src="scripts/prettify/lang-css.js"> </script>
<!--[if lt IE 9]>
<script src="//html5shiv.googlecode.com/svn/trunk/html5.js"></script>
<![endif]-->
<link type="text/css" rel="stylesheet" href="styles/prettify-tomorrow.css">
<link type="text/css" rel="stylesheet" href="styles/jsdoc-default.css">
</head>
<body>
<div id="main">
<h1 class="page-title">Source: core/ping.js</h1>
<section>
<article>
<pre class="prettyprint source linenums"><code>/* eslint no-empty-function: 0 */
/**
* @author Marzavec ( https://github.com/marzavec )
* @summary Legacy support module
* @version 1.0.0
* @description This module is only in place to supress error notices legacy clients may get
* @module ping
*/
/**
* Executes when invoked by a remote client
* @public
* @return {void}
*/
export async function run() { }
/**
* Module meta information
* @public
* @typedef {Object} ping/info
* @property {string} name - Module command name
* @property {string} category - Module category name
* @property {string} description - Information about module
* @property {string} usage - Information about module usage
*/
export const info = {
name: 'ping',
category: 'core',
description: 'This module is only in place to supress error notices legacy clients may get',
usage: 'none',
};
</code></pre>
</article>
</section>
</div>
<nav>
<h2><a href="index.html">Home</a></h2><h3>Modules</h3><ul><li><a href="module-addmod.html">addmod</a></li><li><a href="module-ban.html">ban</a></li><li><a href="module-changecolor.html">changecolor</a></li><li><a href="module-changenick.html">changenick</a></li><li><a href="module-chat.html">chat</a></li><li><a href="module-disconnect.html">disconnect</a></li><li><a href="module-dumb.html">dumb</a></li><li><a href="module-emote.html">emote</a></li><li><a href="module-forcecolor.html">forcecolor</a></li><li><a href="module-help.html">help</a></li><li><a href="module-invite.html">invite</a></li><li><a href="module-join.html">join</a></li><li><a href="module-kick.html">kick</a></li><li><a href="module-listusers.html">listusers</a></li><li><a href="module-morestats.html">morestats</a></li><li><a href="module-ping.html">ping</a></li><li><a href="module-reload.html">reload</a></li><li><a href="module-removemod.html">removemod</a></li><li><a href="module-saveconfig.html">saveconfig</a></li><li><a href="module-session.html">session</a></li><li><a href="module-shout.html">shout</a></li><li><a href="module-socketreply.html">socketreply</a></li><li><a href="module-speak.html">speak</a></li><li><a href="module-stats.html">stats</a></li><li><a href="module-unban.html">unban</a></li><li><a href="module-unbanall.html">unbanall</a></li><li><a href="module-whisper.html">whisper</a></li></ul>
</nav>
<br class="clear">
<footer>
Documentation generated by <a href="https://github.com/jsdoc/jsdoc">JSDoc 3.6.6</a> on Wed Jun 22 2022 10:04:25 GMT-0500 (Central Daylight Time)
</footer>
<script> prettyPrint(); </script>
<script src="scripts/linenumber.js"> </script>
</body>
</html>

View File

@ -0,0 +1,244 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>JSDoc: Source: core/session.js</title>
<script src="scripts/prettify/prettify.js"> </script>
<script src="scripts/prettify/lang-css.js"> </script>
<!--[if lt IE 9]>
<script src="//html5shiv.googlecode.com/svn/trunk/html5.js"></script>
<![endif]-->
<link type="text/css" rel="stylesheet" href="styles/prettify-tomorrow.css">
<link type="text/css" rel="stylesheet" href="styles/jsdoc-default.css">
</head>
<body>
<div id="main">
<h1 class="page-title">Source: core/session.js</h1>
<section>
<article>
<pre class="prettyprint source linenums"><code>/* eslint import/no-cycle: [0, { ignoreExternal: true }] */
/**
* @author Marzavec ( https://github.com/marzavec )
* @summary Create or restore session
* @version 1.0.0
* @description Restore previous state by session or create new session
* @module session
*/
import fs from 'fs';
import jsonwebtoken from 'jsonwebtoken';
import {
verifyNickname,
} from '../utility/_UAC.js';
import {
Errors,
} from '../utility/_Constants.js';
import {
restoreJoin,
} from './join.js';
const SessionLocation = './session.key';
/**
*
* @param {*} socket
* @param {*} core
* @returns {object}
*/
export function getSession(socket, core) {
return jsonwebtoken.sign({
channel: socket.channel,
channels: socket.channels,
color: socket.color,
isBot: socket.isBot,
level: socket.level,
nick: socket.nick,
trip: socket.trip,
userid: socket.userid,
uType: socket.uType, /* @legacy */
muzzled: socket.muzzled || false,
banned: socket.banned || false,
}, core.sessionKey, {
expiresIn: '7 days',
});
}
/**
*
* @param {*} server
* @param {*} socket
* @returns {boolean}
*/
function notifyFailure(server, socket) {
server.reply({
cmd: 'error',
id: Errors.Session.BAD_SESSION,
text: 'Invalid session',
}, socket);
return false;
}
/**
* Executes when invoked by a remote client
* @param {Object} env - Enviroment object with references to core, server, socket &amp; payload
* @public
* @return {void}
*/
export async function run({
core, server, socket, payload,
}) {
if (typeof payload.token === 'undefined') {
return notifyFailure(server, socket);
}
let session = false;
try {
session = jsonwebtoken.verify(payload.token, core.sessionKey);
} catch (err) {
return notifyFailure(server, socket);
}
// validate session
if (typeof session.channel !== 'string') {
return notifyFailure(server, socket);
}
if (Array.isArray(session.channels) === false) {
return notifyFailure(server, socket);
}
if (typeof session.color !== 'string' &amp;&amp; typeof session.color !== 'boolean') {
return notifyFailure(server, socket);
}
if (typeof session.isBot !== 'boolean') {
return notifyFailure(server, socket);
}
if (typeof session.level !== 'number') {
return notifyFailure(server, socket);
}
if (verifyNickname(session.nick) === false) {
return notifyFailure(server, socket);
}
if (typeof session.trip !== 'string') {
return notifyFailure(server, socket);
}
if (typeof session.userid !== 'number') {
return notifyFailure(server, socket);
}
if (typeof session.uType !== 'string') {
return notifyFailure(server, socket);
}
if (typeof session.muzzled !== 'boolean') {
return notifyFailure(server, socket);
}
if (typeof session.banned !== 'boolean') {
return notifyFailure(server, socket);
}
// populate socket info with validated session
socket.channels = [];
socket.color = session.color;
socket.isBot = session.isBot;
socket.level = session.level;
socket.nick = session.nick;
socket.trip = session.trip;
socket.userid = session.userid;
socket.uType = session.uType; /* @legacy */
socket.muzzled = session.muzzled;
socket.banned = session.banned;
socket.hash = server.getSocketHash(socket);
socket.hcProtocol = 2;
// dispatch info
server.reply({
cmd: 'session',
restored: true,
token: getSession(socket, core),
channels: socket.channels,
}, socket);
for (let i = 0, j = session.channels.length; i &lt; j; i += 1) {
restoreJoin({
core,
server,
socket,
channel: session.channels[i],
}, true);
}
return true;
}
/**
* Automatically executes once after server is ready
* @param {Object} core - Reference to core enviroment object
* @public
* @return {void}
*/
export function init(core) {
// load the encryption key if required
if (typeof core.sessionKey === 'undefined') {
core.sessionKey = fs.readFileSync(SessionLocation);
}
}
/**
* Module meta information
* @public
* @typedef {Object} session/info
* @property {string} name - Module command name
* @property {string} category - Module category name
* @property {string} description - Information about module
* @property {string} usage - Information about module usage
*/
export const info = {
name: 'session',
category: 'core',
description: 'Restore previous state by session or create new session',
usage: "API: { cmd: 'session', id: '&lt;previous session>' }",
};
</code></pre>
</article>
</section>
</div>
<nav>
<h2><a href="index.html">Home</a></h2><h3>Modules</h3><ul><li><a href="module-addmod.html">addmod</a></li><li><a href="module-ban.html">ban</a></li><li><a href="module-changecolor.html">changecolor</a></li><li><a href="module-changenick.html">changenick</a></li><li><a href="module-chat.html">chat</a></li><li><a href="module-disconnect.html">disconnect</a></li><li><a href="module-dumb.html">dumb</a></li><li><a href="module-emote.html">emote</a></li><li><a href="module-forcecolor.html">forcecolor</a></li><li><a href="module-help.html">help</a></li><li><a href="module-invite.html">invite</a></li><li><a href="module-join.html">join</a></li><li><a href="module-kick.html">kick</a></li><li><a href="module-listusers.html">listusers</a></li><li><a href="module-morestats.html">morestats</a></li><li><a href="module-ping.html">ping</a></li><li><a href="module-reload.html">reload</a></li><li><a href="module-removemod.html">removemod</a></li><li><a href="module-saveconfig.html">saveconfig</a></li><li><a href="module-session.html">session</a></li><li><a href="module-shout.html">shout</a></li><li><a href="module-socketreply.html">socketreply</a></li><li><a href="module-speak.html">speak</a></li><li><a href="module-stats.html">stats</a></li><li><a href="module-unban.html">unban</a></li><li><a href="module-unbanall.html">unbanall</a></li><li><a href="module-whisper.html">whisper</a></li></ul>
</nav>
<br class="clear">
<footer>
Documentation generated by <a href="https://github.com/jsdoc/jsdoc">JSDoc 3.6.6</a> on Wed Jun 22 2022 10:04:25 GMT-0500 (Central Daylight Time)
</footer>
<script> prettyPrint(); </script>
<script src="scripts/linenumber.js"> </script>
</body>
</html>

View File

@ -0,0 +1,110 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>JSDoc: Source: core/stats.js</title>
<script src="scripts/prettify/prettify.js"> </script>
<script src="scripts/prettify/lang-css.js"> </script>
<!--[if lt IE 9]>
<script src="//html5shiv.googlecode.com/svn/trunk/html5.js"></script>
<![endif]-->
<link type="text/css" rel="stylesheet" href="styles/prettify-tomorrow.css">
<link type="text/css" rel="stylesheet" href="styles/jsdoc-default.css">
</head>
<body>
<div id="main">
<h1 class="page-title">Source: core/stats.js</h1>
<section>
<article>
<pre class="prettyprint source linenums"><code>/**
* @author Marzavec ( https://github.com/marzavec )
* @summary Simple stats
* @version 1.0.0
* @description Sends back legacy server stats to the calling client
* @module stats
*/
/**
* Executes when invoked by a remote client
* @param {Object} env - Enviroment object with references to core, server, socket &amp; payload
* @public
* @return {void}
*/
export async function run({ core, server, socket }) {
// gather connection and channel count
let ips = {};
let channels = {};
// for (const client of server.clients) {
server.clients.forEach((client) => {
if (client.channel) {
channels[client.channel] = true;
ips[client.address] = true;
}
});
const uniqueClientCount = Object.keys(ips).length;
const uniqueChannels = Object.keys(channels).length;
ips = null;
channels = null;
// dispatch info
server.reply({
cmd: 'info',
text: `${uniqueClientCount} unique IPs in ${uniqueChannels} channels`,
channel: socket.channel, // @todo Multichannel
}, socket);
// stats are fun
core.stats.increment('stats-requested');
}
/**
* Module meta information
* @public
* @typedef {Object} stats/info
* @property {string} name - Module command name
* @property {string} category - Module category name
* @property {string} description - Information about module
* @property {string} usage - Information about module usage
*/
export const info = {
name: 'stats',
category: 'core',
description: 'Sends back legacy server stats to the calling client',
usage: `
API: { cmd: 'stats' }`,
};
</code></pre>
</article>
</section>
</div>
<nav>
<h2><a href="index.html">Home</a></h2><h3>Modules</h3><ul><li><a href="module-addmod.html">addmod</a></li><li><a href="module-ban.html">ban</a></li><li><a href="module-changecolor.html">changecolor</a></li><li><a href="module-changenick.html">changenick</a></li><li><a href="module-chat.html">chat</a></li><li><a href="module-disconnect.html">disconnect</a></li><li><a href="module-dumb.html">dumb</a></li><li><a href="module-emote.html">emote</a></li><li><a href="module-forcecolor.html">forcecolor</a></li><li><a href="module-help.html">help</a></li><li><a href="module-invite.html">invite</a></li><li><a href="module-join.html">join</a></li><li><a href="module-kick.html">kick</a></li><li><a href="module-listusers.html">listusers</a></li><li><a href="module-morestats.html">morestats</a></li><li><a href="module-ping.html">ping</a></li><li><a href="module-reload.html">reload</a></li><li><a href="module-removemod.html">removemod</a></li><li><a href="module-saveconfig.html">saveconfig</a></li><li><a href="module-session.html">session</a></li><li><a href="module-shout.html">shout</a></li><li><a href="module-socketreply.html">socketreply</a></li><li><a href="module-speak.html">speak</a></li><li><a href="module-stats.html">stats</a></li><li><a href="module-unban.html">unban</a></li><li><a href="module-unbanall.html">unbanall</a></li><li><a href="module-whisper.html">whisper</a></li></ul>
</nav>
<br class="clear">
<footer>
Documentation generated by <a href="https://github.com/jsdoc/jsdoc">JSDoc 3.6.6</a> on Wed Jun 22 2022 10:04:25 GMT-0500 (Central Daylight Time)
</footer>
<script> prettyPrint(); </script>
<script src="scripts/linenumber.js"> </script>
</body>
</html>

View File

@ -0,0 +1,282 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>JSDoc: Source: core/whisper.js</title>
<script src="scripts/prettify/prettify.js"> </script>
<script src="scripts/prettify/lang-css.js"> </script>
<!--[if lt IE 9]>
<script src="//html5shiv.googlecode.com/svn/trunk/html5.js"></script>
<![endif]-->
<link type="text/css" rel="stylesheet" href="styles/prettify-tomorrow.css">
<link type="text/css" rel="stylesheet" href="styles/jsdoc-default.css">
</head>
<body>
<div id="main">
<h1 class="page-title">Source: core/whisper.js</h1>
<section>
<article>
<pre class="prettyprint source linenums"><code>/**
* @author Marzavec ( https://github.com/marzavec )
* @summary Send whisper
* @version 1.0.0
* @description Display text on target users screen that only they can see
* @module whisper
* @todo This should be changed to it's own event type, instead of `info`
and accept a `userid` rather than `nick`
*/
import {
findUser,
} from '../utility/_Channels.js';
import {
Errors,
} from '../utility/_Constants.js';
import {
legacyWhisperOut,
legacyWhisperReply,
} from '../utility/_LegacyFunctions.js';
/**
* Check and trim string provided by remote client
* @param {string} text - Subject string
* @private
* @todo Move into utility module
* @return {string|boolean}
*/
const parseText = (text) => {
// verifies user input is text
if (typeof text !== 'string') {
return false;
}
let sanitizedText = text;
// strip newlines from beginning and end
sanitizedText = sanitizedText.replace(/^\s*\n|^\s+$|\n\s*$/g, '');
// replace 3+ newlines with just 2 newlines
sanitizedText = sanitizedText.replace(/\n{3,}/g, '\n\n');
return sanitizedText;
};
/**
* Executes when invoked by a remote client
* @param {Object} env - Enviroment object with references to core, server, socket &amp; payload
* @public
* @return {void}
*/
export async function run({ server, socket, payload }) {
// if this is a legacy client add missing params to payload
if (socket.hcProtocol === 1) {
payload.channel = socket.channel; // eslint-disable-line no-param-reassign
}
// verify user input
const text = parseText(payload.text);
if (!text) {
// lets not send objects or empty text, yea?
return server.police.frisk(socket.address, 13);
}
// check for spam
const score = text.length / 83 / 4;
if (server.police.frisk(socket.address, score)) {
return server.reply({
cmd: 'warn', // @todo Add numeric error code as `id`
text: 'You are sending too much text. Wait a moment and try again.\nPress the up arrow key to restore your last message.',
channel: socket.channel, // @todo Multichannel
}, socket);
}
const targetUser = findUser(server, payload);
if (!targetUser) {
return server.reply({
cmd: 'warn',
text: 'Could not find user in that channel',
id: Errors.Global.UNKNOWN_USER,
channel: socket.channel, // @todo Multichannel
}, socket);
}
const outgoingPayload = {
cmd: 'whisper',
channel: socket.channel, // @todo Multichannel
from: socket.userid,
to: targetUser.userid,
text,
};
// send invite notice to target client
if (targetUser.hcProtocol === 1) {
server.reply(legacyWhisperOut(outgoingPayload, socket), targetUser);
} else {
server.reply(outgoingPayload, targetUser);
}
// send invite notice to this client
if (socket.hcProtocol === 1) {
server.reply(legacyWhisperReply(outgoingPayload, targetUser.nick), socket);
} else {
server.reply(outgoingPayload, socket);
}
targetUser.whisperReply = socket.nick;
return true;
}
/**
* Automatically executes once after server is ready to register this modules hooks
* @param {Object} server - Reference to server enviroment object
* @public
* @return {void}
*/
export function initHooks(server) {
server.registerHook('in', 'chat', this.whisperCheck.bind(this), 20);
}
/**
* Executes every time an incoming chat command is invoked;
* hooks chat commands checking for /whisper
* @param {Object} env - Enviroment object with references to core, server, socket &amp; payload
* @public
* @return {{Object|boolean|string}} Object = same/altered payload,
* false = suppress action,
* string = error
*/
export function whisperCheck({
core, server, socket, payload,
}) {
if (typeof payload.text !== 'string') {
return false;
}
if (payload.text.startsWith('/whisper ') || payload.text.startsWith('/w ')) {
const input = payload.text.split(' ');
// If there is no nickname target parameter
if (!input[1]) {
server.reply({
cmd: 'warn', // @todo Add numeric error code as `id`
text: 'Refer to `/help whisper` for instructions on how to use this command.',
channel: socket.channel, // @todo Multichannel
}, socket);
return false;
}
const target = input[1].replace(/@/g, '');
input.splice(0, 2);
const whisperText = input.join(' ');
this.run({
core,
server,
socket,
payload: {
cmd: 'whisper',
channel: socket.channel, // @todo Multichannel
nick: target,
text: whisperText,
},
});
return false;
}
if (payload.text.startsWith('/reply ') || payload.text.startsWith('/r ')) {
if (typeof socket.whisperReply === 'undefined') {
server.reply({
cmd: 'warn', // @todo Add numeric error code as `id`
text: 'Cannot reply to nobody',
channel: socket.channel, // @todo Multichannel
}, socket);
return false;
}
const input = payload.text.split(' ');
input.splice(0, 1);
const whisperText = input.join(' ');
this.run({
core,
server,
socket,
payload: {
cmd: 'whisper',
nick: socket.whisperReply,
channel: socket.channel, // @todo Multichannel
text: whisperText,
},
});
return false;
}
return payload;
}
/**
* The following payload properties are required to invoke this module:
* "nick", "text"
* @public
* @typedef {Array} whisper/requiredData
*/
export const requiredData = ['nick', 'text'];
/**
* Module meta information
* @public
* @typedef {Object} whisper/info
* @property {string} name - Module command name
* @property {string} category - Module category name
* @property {string} description - Information about module
* @property {string} usage - Information about module usage
*/
export const info = {
name: 'whisper',
category: 'core',
description: 'Display text on target users screen that only they can see',
usage: `
API: { cmd: 'whisper', nick: '&lt;target name>', text: '&lt;text to whisper>' }
Text: /whisper &lt;target name> &lt;text to whisper>
Text: /w &lt;target name> &lt;text to whisper>
Alt Text: /reply &lt;text to whisper, this will auto reply to the last person who whispered to you>
Alt Text: /r &lt;text to whisper, this will auto reply to the last person who whispered to you>`,
};
</code></pre>
</article>
</section>
</div>
<nav>
<h2><a href="index.html">Home</a></h2><h3>Modules</h3><ul><li><a href="module-addmod.html">addmod</a></li><li><a href="module-ban.html">ban</a></li><li><a href="module-changecolor.html">changecolor</a></li><li><a href="module-changenick.html">changenick</a></li><li><a href="module-chat.html">chat</a></li><li><a href="module-disconnect.html">disconnect</a></li><li><a href="module-dumb.html">dumb</a></li><li><a href="module-emote.html">emote</a></li><li><a href="module-forcecolor.html">forcecolor</a></li><li><a href="module-help.html">help</a></li><li><a href="module-invite.html">invite</a></li><li><a href="module-join.html">join</a></li><li><a href="module-kick.html">kick</a></li><li><a href="module-listusers.html">listusers</a></li><li><a href="module-morestats.html">morestats</a></li><li><a href="module-ping.html">ping</a></li><li><a href="module-reload.html">reload</a></li><li><a href="module-removemod.html">removemod</a></li><li><a href="module-saveconfig.html">saveconfig</a></li><li><a href="module-session.html">session</a></li><li><a href="module-shout.html">shout</a></li><li><a href="module-socketreply.html">socketreply</a></li><li><a href="module-speak.html">speak</a></li><li><a href="module-stats.html">stats</a></li><li><a href="module-unban.html">unban</a></li><li><a href="module-unbanall.html">unbanall</a></li><li><a href="module-whisper.html">whisper</a></li></ul>
</nav>
<br class="clear">
<footer>
Documentation generated by <a href="https://github.com/jsdoc/jsdoc">JSDoc 3.6.6</a> on Wed Jun 22 2022 10:04:25 GMT-0500 (Central Daylight Time)
</footer>
<script> prettyPrint(); </script>
<script src="scripts/linenumber.js"> </script>
</body>
</html>

Binary file not shown.

File diff suppressed because it is too large Load Diff

After

Width:  |  Height:  |  Size: 116 KiB

Binary file not shown.

Binary file not shown.

File diff suppressed because it is too large Load Diff

After

Width:  |  Height:  |  Size: 118 KiB

Binary file not shown.

Binary file not shown.

File diff suppressed because it is too large Load Diff

After

Width:  |  Height:  |  Size: 120 KiB

Binary file not shown.

Binary file not shown.

File diff suppressed because it is too large Load Diff

After

Width:  |  Height:  |  Size: 114 KiB

Binary file not shown.

Binary file not shown.

File diff suppressed because it is too large Load Diff

After

Width:  |  Height:  |  Size: 120 KiB

Binary file not shown.

Binary file not shown.

File diff suppressed because it is too large Load Diff

After

Width:  |  Height:  |  Size: 117 KiB

Binary file not shown.

105
documentation/index.html Normal file
View File

@ -0,0 +1,105 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>JSDoc: Home</title>
<script src="scripts/prettify/prettify.js"> </script>
<script src="scripts/prettify/lang-css.js"> </script>
<!--[if lt IE 9]>
<script src="//html5shiv.googlecode.com/svn/trunk/html5.js"></script>
<![endif]-->
<link type="text/css" rel="stylesheet" href="styles/prettify-tomorrow.css">
<link type="text/css" rel="stylesheet" href="styles/jsdoc-default.css">
</head>
<body>
<div id="main">
<h1 class="page-title">Home</h1>
<h3> </h3>
<section>
<article><h1>hack.chat</h1>
<p><a href="https://hack.chat/">hack.chat</a> is a minimal, distraction-free, accountless, logless, disappearing chat service which is easily deployable as your own service. The current client comes bundled with LaTeX rendering provided by <a href="https://github.com/Khan/KaTeX">KaTeX</a> and code syntax highlighting provided by <a href="https://github.com/isagalaev/highlight.js">highlight.js</a>.</p>
<p>A list of software developed for the hack.chat framework can be found at the <a href="https://github.com/hack-chat/3rd-party-software-list">3rd party software list</a> repository. This includes bots, clients, docker containers, etc.</p>
<p>This is a backwards compatible continuation of the <a href="https://github.com/AndrewBelt/hack.chat">work by Andrew Belt</a>. The server code has been updated to ES6 along with several new features including new commands and hot-reload of the commands/protocol. There is also <a href="documentation/index.html">documentation</a>.</p>
<h1>Installation</h1>
<h2>Prerequisites</h2>
<ul>
<li><a href="https://nodejs.org/">node.js v16.14.0</a> or higher</li>
<li><a href="https://nodejs.org/">npm 8.5.4</a> or higher</li>
</ul>
<h2>Developer Installation</h2>
<ol>
<li><a href="https://help.github.com/articles/cloning-a-repository/">Clone</a> the repository: <code>git clone https://github.com/hack-chat/main.git</code></li>
<li>Change the directory: <code>cd main</code></li>
<li>Install the dependencies: <code>npm install</code></li>
<li>Launch: <code>npm start</code></li>
</ol>
<h2>Live Deployment Installation</h2>
<p>See <a href="documentation/DEPLOY.md">DEPLOY.md</a></p>
<h1>Contributing</h1>
<ul>
<li>Use two space indents.</li>
<li>Name files in camelCase.</li>
</ul>
<h1>Credits</h1>
<ul>
<li><a href="https://github.com/marzavec"><strong>Marzavec</strong></a> - <em>Initial work</em></li>
<li><a href="https://github.com/MinusGix"><strong>MinusGix</strong></a> - <em>Base updates</em></li>
<li><a href="https://github.com/neelkamath"><strong>Neel Kamath</strong></a> - <em>Base Documentation</em></li>
<li><a href="https://github.com/po5i"><strong>Carlos Villavicencio</strong></a> - <em>Syntax Highlighting Integration</em></li>
<li><a href="https://github.com/OpSimple"><strong>OpSimple</strong></a> - <em>Modules Added: dumb.js &amp; speak.js</em></li>
<li><a href="https://github.com/AndrewBelt"><strong>Andrew Belt</strong></a>, for original base work</li>
<li><a href="https://github.com/wwandrew"><strong>wwandrew</strong></a>, for finding server flaws (including attack vectors) and submitting <s><em><strong>incredibly detailed</strong></em></s> bug reports</li>
<li><a href="https://github.com/hack-chat/main/graphs/contributors"><strong>Everyone else</strong></a> who participated in this project.</li>
</ul>
<h1>License</h1>
<p>This project is licensed under the <a href="LICENSE">MIT License</a>.</p></article>
</section>
</div>
<nav>
<h2><a href="index.html">Home</a></h2><h3>Modules</h3><ul><li><a href="module-addmod.html">addmod</a></li><li><a href="module-ban.html">ban</a></li><li><a href="module-changecolor.html">changecolor</a></li><li><a href="module-changenick.html">changenick</a></li><li><a href="module-chat.html">chat</a></li><li><a href="module-disconnect.html">disconnect</a></li><li><a href="module-dumb.html">dumb</a></li><li><a href="module-emote.html">emote</a></li><li><a href="module-forcecolor.html">forcecolor</a></li><li><a href="module-help.html">help</a></li><li><a href="module-invite.html">invite</a></li><li><a href="module-join.html">join</a></li><li><a href="module-kick.html">kick</a></li><li><a href="module-listusers.html">listusers</a></li><li><a href="module-morestats.html">morestats</a></li><li><a href="module-ping.html">ping</a></li><li><a href="module-reload.html">reload</a></li><li><a href="module-removemod.html">removemod</a></li><li><a href="module-saveconfig.html">saveconfig</a></li><li><a href="module-session.html">session</a></li><li><a href="module-shout.html">shout</a></li><li><a href="module-socketreply.html">socketreply</a></li><li><a href="module-speak.html">speak</a></li><li><a href="module-stats.html">stats</a></li><li><a href="module-unban.html">unban</a></li><li><a href="module-unbanall.html">unbanall</a></li><li><a href="module-whisper.html">whisper</a></li></ul>
</nav>
<br class="clear">
<footer>
Documentation generated by <a href="https://github.com/jsdoc/jsdoc">JSDoc 3.6.6</a> on Wed Jun 22 2022 10:04:25 GMT-0500 (Central Daylight Time)
</footer>
<script> prettyPrint(); </script>
<script src="scripts/linenumber.js"> </script>
</body>
</html>

View File

@ -0,0 +1,117 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>JSDoc: Source: internal/disconnect.js</title>
<script src="scripts/prettify/prettify.js"> </script>
<script src="scripts/prettify/lang-css.js"> </script>
<!--[if lt IE 9]>
<script src="//html5shiv.googlecode.com/svn/trunk/html5.js"></script>
<![endif]-->
<link type="text/css" rel="stylesheet" href="styles/prettify-tomorrow.css">
<link type="text/css" rel="stylesheet" href="styles/jsdoc-default.css">
</head>
<body>
<div id="main">
<h1 class="page-title">Source: internal/disconnect.js</h1>
<section>
<article>
<pre class="prettyprint source linenums"><code>/**
* @author Marzavec ( https://github.com/marzavec )
* @summary Disconnection handler
* @version 1.0.0
* @description The server invokes this module each time a websocket connection is disconnected
* @module disconnect
*/
import {
socketInChannel,
} from '../utility/_Channels.js';
/**
* Executes when invoked by a remote client
* @param {Object} env - Enviroment object with references to core, server, socket &amp; payload
* @public
* @return {void}
*/
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);
}
// send leave notice to client peers
// @todo Multichannel update
if (socket.channel) {
const isDuplicate = socketInChannel(server, socket.channel, socket);
if (isDuplicate === false) {
server.broadcast({
cmd: 'onlineRemove',
nick: socket.nick,
}, { channel: socket.channel });
}
}
// commit close just in case
socket.terminate();
return true;
}
/**
* The following payload properties are required to invoke this module:
* "cmdKey"
* @public
* @typedef {Array} disconnect/requiredData
*/
export const requiredData = ['cmdKey'];
/**
* Module meta information
* @public
* @typedef {Object} disconnect/info
* @property {string} name - Module command name
* @property {string} category - Module category name
* @property {string} description - Information about module
* @property {string} usage - Information about module usage
*/
export const info = {
name: 'disconnect',
category: 'internal',
description: 'Internally used to relay disconnect events to clients',
usage: 'Internal Use Only',
};
</code></pre>
</article>
</section>
</div>
<nav>
<h2><a href="index.html">Home</a></h2><h3>Modules</h3><ul><li><a href="module-addmod.html">addmod</a></li><li><a href="module-ban.html">ban</a></li><li><a href="module-changecolor.html">changecolor</a></li><li><a href="module-changenick.html">changenick</a></li><li><a href="module-chat.html">chat</a></li><li><a href="module-disconnect.html">disconnect</a></li><li><a href="module-dumb.html">dumb</a></li><li><a href="module-emote.html">emote</a></li><li><a href="module-forcecolor.html">forcecolor</a></li><li><a href="module-help.html">help</a></li><li><a href="module-invite.html">invite</a></li><li><a href="module-join.html">join</a></li><li><a href="module-kick.html">kick</a></li><li><a href="module-listusers.html">listusers</a></li><li><a href="module-morestats.html">morestats</a></li><li><a href="module-ping.html">ping</a></li><li><a href="module-reload.html">reload</a></li><li><a href="module-removemod.html">removemod</a></li><li><a href="module-saveconfig.html">saveconfig</a></li><li><a href="module-session.html">session</a></li><li><a href="module-shout.html">shout</a></li><li><a href="module-socketreply.html">socketreply</a></li><li><a href="module-speak.html">speak</a></li><li><a href="module-stats.html">stats</a></li><li><a href="module-unban.html">unban</a></li><li><a href="module-unbanall.html">unbanall</a></li><li><a href="module-whisper.html">whisper</a></li></ul>
</nav>
<br class="clear">
<footer>
Documentation generated by <a href="https://github.com/jsdoc/jsdoc">JSDoc 3.6.6</a> on Wed Jun 22 2022 10:04:25 GMT-0500 (Central Daylight Time)
</footer>
<script> prettyPrint(); </script>
<script src="scripts/linenumber.js"> </script>
</body>
</html>

View File

@ -0,0 +1,102 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>JSDoc: Source: internal/socketreply.js</title>
<script src="scripts/prettify/prettify.js"> </script>
<script src="scripts/prettify/lang-css.js"> </script>
<!--[if lt IE 9]>
<script src="//html5shiv.googlecode.com/svn/trunk/html5.js"></script>
<![endif]-->
<link type="text/css" rel="stylesheet" href="styles/prettify-tomorrow.css">
<link type="text/css" rel="stylesheet" href="styles/jsdoc-default.css">
</head>
<body>
<div id="main">
<h1 class="page-title">Source: internal/socketreply.js</h1>
<section>
<article>
<pre class="prettyprint source linenums"><code>/**
* @author Marzavec ( https://github.com/marzavec )
* @summary Bridge warning events to a user
* @version 1.0.0
* @description If a warning occurs within the server, this module will relay the warning to the
* client
* @module socketreply
*/
/**
* Executes when invoked by a remote client
* @param {Object} env - Enviroment object with references to core, server, socket &amp; payload
* @public
* @return {void}
*/
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);
}
// send warning to target socket
return server.reply({
cmd: 'warn',
text: payload.text,
}, socket);
}
/**
* The following payload properties are required to invoke this module:
* "cmdKey", "text"
* @public
* @typedef {Array} socketreply/requiredData
*/
export const requiredData = ['cmdKey', 'text'];
/**
* Module meta information
* @public
* @typedef {Object} socketreply/info
* @property {string} name - Module command name
* @property {string} category - Module category name
* @property {string} description - Information about module
* @property {string} usage - Information about module usage
*/
export const info = {
name: 'socketreply',
category: 'internal',
description: 'Internally used to relay warnings to clients',
usage: 'Internal Use Only',
};
</code></pre>
</article>
</section>
</div>
<nav>
<h2><a href="index.html">Home</a></h2><h3>Modules</h3><ul><li><a href="module-addmod.html">addmod</a></li><li><a href="module-ban.html">ban</a></li><li><a href="module-changecolor.html">changecolor</a></li><li><a href="module-changenick.html">changenick</a></li><li><a href="module-chat.html">chat</a></li><li><a href="module-disconnect.html">disconnect</a></li><li><a href="module-dumb.html">dumb</a></li><li><a href="module-emote.html">emote</a></li><li><a href="module-forcecolor.html">forcecolor</a></li><li><a href="module-help.html">help</a></li><li><a href="module-invite.html">invite</a></li><li><a href="module-join.html">join</a></li><li><a href="module-kick.html">kick</a></li><li><a href="module-listusers.html">listusers</a></li><li><a href="module-morestats.html">morestats</a></li><li><a href="module-ping.html">ping</a></li><li><a href="module-reload.html">reload</a></li><li><a href="module-removemod.html">removemod</a></li><li><a href="module-saveconfig.html">saveconfig</a></li><li><a href="module-session.html">session</a></li><li><a href="module-shout.html">shout</a></li><li><a href="module-socketreply.html">socketreply</a></li><li><a href="module-speak.html">speak</a></li><li><a href="module-stats.html">stats</a></li><li><a href="module-unban.html">unban</a></li><li><a href="module-unbanall.html">unbanall</a></li><li><a href="module-whisper.html">whisper</a></li></ul>
</nav>
<br class="clear">
<footer>
Documentation generated by <a href="https://github.com/jsdoc/jsdoc">JSDoc 3.6.6</a> on Wed Jun 22 2022 10:04:25 GMT-0500 (Central Daylight Time)
</footer>
<script> prettyPrint(); </script>
<script src="scripts/linenumber.js"> </script>
</body>
</html>

View File

@ -0,0 +1,166 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>JSDoc: Source: mod/ban.js</title>
<script src="scripts/prettify/prettify.js"> </script>
<script src="scripts/prettify/lang-css.js"> </script>
<!--[if lt IE 9]>
<script src="//html5shiv.googlecode.com/svn/trunk/html5.js"></script>
<![endif]-->
<link type="text/css" rel="stylesheet" href="styles/prettify-tomorrow.css">
<link type="text/css" rel="stylesheet" href="styles/jsdoc-default.css">
</head>
<body>
<div id="main">
<h1 class="page-title">Source: mod/ban.js</h1>
<section>
<article>
<pre class="prettyprint source linenums"><code>/**
* @author Marzavec ( https://github.com/marzavec )
* @summary Ban a user
* @version 1.0.0
* @description Bans target user by name
* @module ban
*/
import {
isModerator,
getUserDetails,
levels,
} from '../utility/_UAC.js';
import {
Errors,
} from '../utility/_Constants.js';
import {
findUser,
} from '../utility/_Channels.js';
/**
* Executes when invoked by a remote client
* @param {Object} env - Enviroment object with references to core, server, socket &amp; payload
* @public
* @return {void}
*/
export async function run({
core, server, socket, payload,
}) {
// increase rate limit chance and ignore if not admin or mod
if (!isModerator(socket.level)) {
return server.police.frisk(socket.address, 10);
}
// check user input
if (socket.hcProtocol === 1) {
if (typeof payload.nick !== 'string') {
return false;
}
payload.channel = socket.channel; // eslint-disable-line no-param-reassign
} else if (typeof payload.userid !== 'number') {
return false;
}
// find target user
const targetUser = findUser(server, payload);
if (!targetUser) {
return server.reply({
cmd: 'warn',
text: 'Could not find user in that channel',
id: Errors.Global.UNKNOWN_USER,
channel: socket.channel, // @todo Multichannel
}, socket);
}
const targetNick = targetUser.nick;
// i guess banning mods or admins isn't the best idea?
if (targetUser.level >= socket.level) {
return server.reply({
cmd: 'warn',
text: 'Cannot ban other users of the same level, how rude',
id: Errors.Global.PERMISSION,
channel: socket.channel, // @todo Multichannel
}, socket);
}
// commit arrest record
server.police.arrest(targetUser.address, targetUser.hash);
console.log(`${socket.nick} [${socket.trip}] banned ${targetNick} in ${socket.channel}`);
// notify normal users
server.broadcast({
cmd: 'info',
text: `Banned ${targetNick}`,
user: getUserDetails(targetUser),
channel: socket.channel, // @todo Multichannel
}, { channel: socket.channel, level: (level) => level &lt; levels.moderator });
// notify mods
server.broadcast({
cmd: 'info',
text: `${socket.nick}#${socket.trip} banned ${targetNick} in ${payload.channel}, userhash: ${targetUser.hash}`,
channel: socket.channel, // @todo Multichannel
inChannel: payload.channel,
user: getUserDetails(targetUser),
banner: getUserDetails(socket),
}, { level: isModerator });
// force connection closed
targetUser.terminate();
// stats are fun
core.stats.increment('users-banned');
return true;
}
/**
* Module meta information
* @public
* @typedef {Object} ban/info
* @property {string} name - Module command name
* @property {string} category - Module category name
* @property {string} description - Information about module
* @property {string} usage - Information about module usage
*/
export const info = {
name: 'ban',
category: 'moderators',
description: 'Bans target user by name',
usage: `
API: { cmd: 'ban', nick: '&lt;target nickname>' }`,
};
</code></pre>
</article>
</section>
</div>
<nav>
<h2><a href="index.html">Home</a></h2><h3>Modules</h3><ul><li><a href="module-addmod.html">addmod</a></li><li><a href="module-ban.html">ban</a></li><li><a href="module-changecolor.html">changecolor</a></li><li><a href="module-changenick.html">changenick</a></li><li><a href="module-chat.html">chat</a></li><li><a href="module-disconnect.html">disconnect</a></li><li><a href="module-dumb.html">dumb</a></li><li><a href="module-emote.html">emote</a></li><li><a href="module-forcecolor.html">forcecolor</a></li><li><a href="module-help.html">help</a></li><li><a href="module-invite.html">invite</a></li><li><a href="module-join.html">join</a></li><li><a href="module-kick.html">kick</a></li><li><a href="module-listusers.html">listusers</a></li><li><a href="module-morestats.html">morestats</a></li><li><a href="module-ping.html">ping</a></li><li><a href="module-reload.html">reload</a></li><li><a href="module-removemod.html">removemod</a></li><li><a href="module-saveconfig.html">saveconfig</a></li><li><a href="module-session.html">session</a></li><li><a href="module-shout.html">shout</a></li><li><a href="module-socketreply.html">socketreply</a></li><li><a href="module-speak.html">speak</a></li><li><a href="module-stats.html">stats</a></li><li><a href="module-unban.html">unban</a></li><li><a href="module-unbanall.html">unbanall</a></li><li><a href="module-whisper.html">whisper</a></li></ul>
</nav>
<br class="clear">
<footer>
Documentation generated by <a href="https://github.com/jsdoc/jsdoc">JSDoc 3.6.6</a> on Wed Jun 22 2022 10:04:25 GMT-0500 (Central Daylight Time)
</footer>
<script> prettyPrint(); </script>
<script src="scripts/linenumber.js"> </script>
</body>
</html>

View File

@ -0,0 +1,424 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>JSDoc: Source: mod/dumb.js</title>
<script src="scripts/prettify/prettify.js"> </script>
<script src="scripts/prettify/lang-css.js"> </script>
<!--[if lt IE 9]>
<script src="//html5shiv.googlecode.com/svn/trunk/html5.js"></script>
<![endif]-->
<link type="text/css" rel="stylesheet" href="styles/prettify-tomorrow.css">
<link type="text/css" rel="stylesheet" href="styles/jsdoc-default.css">
</head>
<body>
<div id="main">
<h1 class="page-title">Source: mod/dumb.js</h1>
<section>
<article>
<pre class="prettyprint source linenums"><code>/* eslint no-param-reassign: 0 */
/* eslint no-multi-assign: 0 */
/**
* @author OpSimple ( https://github.com/OpSimple )
* @summary Muzzle a user
* @version 1.0.0
* @description Globally shadow mute a connection. Optional allies array will see muted messages.
* @module dumb
*/
import {
isModerator,
} from '../utility/_UAC.js';
import {
findUser,
} from '../utility/_Channels.js';
import {
Errors,
} from '../utility/_Constants.js';
import {
legacyInviteReply,
legacyWhisperReply,
} from '../utility/_LegacyFunctions.js';
/**
* Returns the channel that should be invited to.
* @param {any} channel
* @private
* @return {string}
*/
export function getChannel(channel = undefined) {
if (typeof channel === 'string') {
return channel;
}
return Math.random().toString(36).substr(2, 8);
}
/**
* Check and trim string provided by remote client
* @param {string} text - Subject string
* @private
* @todo Move into utility module
* @return {string|boolean}
*/
const parseText = (text) => {
// verifies user input is text
if (typeof text !== 'string') {
return false;
}
let sanitizedText = text;
// strip newlines from beginning and end
sanitizedText = sanitizedText.replace(/^\s*\n|^\s+$|\n\s*$/g, '');
// replace 3+ newlines with just 2 newlines
sanitizedText = sanitizedText.replace(/\n{3,}/g, '\n\n');
return sanitizedText;
};
/**
* Automatically executes once after server is ready
* @param {Object} core - Reference to core enviroment object
* @public
* @return {void}
*/
export function init(core) {
if (typeof core.muzzledHashes === 'undefined') {
core.muzzledHashes = {};
}
}
/**
* Executes when invoked by a remote client
* @param {Object} env - Enviroment object with references to core, server, socket &amp; payload
* @public
* @return {void}
*/
export async function run({
core, server, socket, payload,
}) {
// increase rate limit chance and ignore if not admin or mod
if (!isModerator(socket.level)) {
return server.police.frisk(socket.address, 10);
}
// check user input
if (socket.hcProtocol === 1) {
if (typeof payload.nick !== 'string') {
return true;
}
payload.channel = socket.channel;
} else if (typeof payload.userid !== 'number') {
return true;
}
// find target user
const targetUser = findUser(server, payload);
if (!targetUser) {
return server.reply({
cmd: 'warn',
text: 'Could not find user in that channel',
id: Errors.Global.UNKNOWN_USER,
channel: socket.channel, // @todo Multichannel
}, socket);
}
// likely dont need this, muting mods and admins is fine
if (targetUser.level >= socket.level) {
return server.reply({
cmd: 'warn',
text: 'This trick wont work on users of the same level',
id: Errors.Global.PERMISSION,
channel: socket.channel, // @todo Multichannel
}, socket);
}
// store hash in mute list
const record = core.muzzledHashes[targetUser.hash] = {
dumb: true,
};
// store allies if needed
if (payload.allies &amp;&amp; Array.isArray(payload.allies)) {
record.allies = payload.allies;
}
// notify mods
server.broadcast({
cmd: 'info',
text: `${socket.nick}#${socket.trip} muzzled ${targetUser.nick} in ${payload.channel}, userhash: ${targetUser.hash}`,
channel: false, // @todo Multichannel, false for global
}, { level: isModerator });
return true;
}
/**
* Automatically executes once after server is ready to register this modules hooks
* @param {Object} server - Reference to server enviroment object
* @public
* @return {void}
*/
export function initHooks(server) {
server.registerHook('in', 'chat', this.chatCheck.bind(this), 10);
server.registerHook('in', 'invite', this.inviteCheck.bind(this), 10);
server.registerHook('in', 'whisper', this.whisperCheck.bind(this), 10);
}
/**
* Executes every time an incoming chat command is invoked;
* hook incoming chat commands, shadow-prevent chat if they are muzzled
* @param {Object} env - Enviroment object with references to core, server, socket &amp; payload
* @public
* @return {{Object|boolean|string}} Object = same/altered payload,
* false = suppress action,
* string = error
*/
export function chatCheck({
core, server, socket, payload,
}) {
if (typeof payload.text !== 'string') {
return false;
}
if (core.muzzledHashes[socket.hash]) {
// build fake chat payload
const outgoingPayload = {
cmd: 'chat',
nick: socket.nick, /* @legacy */
uType: socket.uType, /* @legacy */
userid: socket.userid,
channel: socket.channel,
text: payload.text,
level: socket.level,
};
if (socket.trip) {
outgoingPayload.trip = socket.trip;
}
if (socket.color) {
outgoingPayload.color = socket.color;
}
// broadcast to any duplicate connections in channel
server.broadcast(outgoingPayload, { channel: socket.channel, hash: socket.hash });
// broadcast to allies, if any
if (core.muzzledHashes[socket.hash].allies) {
server.broadcast(
outgoingPayload,
{
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.address, 9);
return false;
}
return payload;
}
/**
* Executes every time an incoming chat command is invoked;
* shadow-prevent all invites from muzzled users
* @param {Object} env - Enviroment object with references to core, server, socket &amp; payload
* @public
* @return {{Object|boolean|string}} Object = same/altered payload,
* false = suppress action,
* string = error
*/
export function inviteCheck({
core, server, socket, payload,
}) {
if (core.muzzledHashes[socket.hash]) {
// check for spam
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.',
id: Errors.Invite.RATELIMIT,
channel: socket.channel, // @todo Multichannel
}, socket);
}
// verify user input
// if this is a legacy client add missing params to payload
if (socket.hcProtocol === 1) {
if (typeof socket.channel === 'undefined' || typeof payload.nick !== 'string') {
return true;
}
payload.channel = socket.channel; // eslint-disable-line no-param-reassign
} else if (typeof payload.userid !== 'number' || typeof payload.channel !== 'string') {
return true;
}
// @todo Verify this socket is part of payload.channel - multichannel patch
// find target user
const targetUser = findUser(server, payload);
if (!targetUser) {
return server.reply({
cmd: 'warn',
text: 'Could not find user in that channel',
id: Errors.Global.UNKNOWN_USER,
channel: socket.channel, // @todo Multichannel
}, socket);
}
// generate common channel
const channel = getChannel(payload.to);
// build invite
const outgoingPayload = {
cmd: 'invite',
channel: socket.channel, // @todo Multichannel
from: socket.userid,
to: targetUser.userid,
inviteChannel: channel,
};
// send invite notice to this client
if (socket.hcProtocol === 1) {
server.reply(legacyInviteReply(outgoingPayload, targetUser.nick), socket);
} else {
server.reply(outgoingPayload, socket);
}
return false;
}
return payload;
}
/**
* Executes every time an incoming chat command is invoked;
* shadow-prevent all whispers from muzzled users
* @param {Object} env - Enviroment object with references to core, server, socket &amp; payload
* @public
* @return {{Object|boolean|string}} Object = same/altered payload,
* false = suppress action,
* string = error
*/
export function whisperCheck({
core, server, socket, payload,
}) {
if (core.muzzledHashes[socket.hash]) {
// if this is a legacy client add missing params to payload
if (socket.hcProtocol === 1) {
payload.channel = socket.channel; // eslint-disable-line no-param-reassign
}
// verify user input
const text = parseText(payload.text);
if (!text) {
// lets not send objects or empty text, yea?
return server.police.frisk(socket.address, 13);
}
// check for spam
const score = text.length / 83 / 4;
if (server.police.frisk(socket.address, score)) {
return server.reply({
cmd: 'warn', // @todo Add numeric error code as `id`
text: 'You are sending too much text. Wait a moment and try again.\nPress the up arrow key to restore your last message.',
channel: socket.channel, // @todo Multichannel
}, socket);
}
const targetUser = findUser(server, payload);
if (!targetUser) {
return server.reply({
cmd: 'warn',
text: 'Could not find user in that channel',
id: Errors.Global.UNKNOWN_USER,
channel: socket.channel, // @todo Multichannel
}, socket);
}
const outgoingPayload = {
cmd: 'whisper',
channel: socket.channel, // @todo Multichannel
from: socket.userid,
to: targetUser.userid,
text,
};
// send invite notice to this client
if (socket.hcProtocol === 1) {
server.reply(legacyWhisperReply(outgoingPayload, targetUser.nick), socket);
} else {
server.reply(outgoingPayload, socket);
}
targetUser.whisperReply = socket.nick;
return false;
}
return payload;
}
/**
* Module meta information
* @public
* @typedef {Object} dumb/info
* @property {string} name - Module command name
* @property {string} category - Module category name
* @property {string} description - Information about module
* @property {string} usage - Information about module usage
*/
export const info = {
name: 'dumb',
category: 'moderators',
description: 'Globally shadow mute a connection. Optional allies array will see muted messages.',
aliases: ['muzzle', 'mute'],
usage: `
API: { cmd: 'dumb', nick: '&lt;target nick>', allies: ['&lt;optional nick array>', ...] }`,
};
</code></pre>
</article>
</section>
</div>
<nav>
<h2><a href="index.html">Home</a></h2><h3>Modules</h3><ul><li><a href="module-addmod.html">addmod</a></li><li><a href="module-ban.html">ban</a></li><li><a href="module-changecolor.html">changecolor</a></li><li><a href="module-changenick.html">changenick</a></li><li><a href="module-chat.html">chat</a></li><li><a href="module-disconnect.html">disconnect</a></li><li><a href="module-dumb.html">dumb</a></li><li><a href="module-emote.html">emote</a></li><li><a href="module-forcecolor.html">forcecolor</a></li><li><a href="module-help.html">help</a></li><li><a href="module-invite.html">invite</a></li><li><a href="module-join.html">join</a></li><li><a href="module-kick.html">kick</a></li><li><a href="module-listusers.html">listusers</a></li><li><a href="module-morestats.html">morestats</a></li><li><a href="module-ping.html">ping</a></li><li><a href="module-reload.html">reload</a></li><li><a href="module-removemod.html">removemod</a></li><li><a href="module-saveconfig.html">saveconfig</a></li><li><a href="module-session.html">session</a></li><li><a href="module-shout.html">shout</a></li><li><a href="module-socketreply.html">socketreply</a></li><li><a href="module-speak.html">speak</a></li><li><a href="module-stats.html">stats</a></li><li><a href="module-unban.html">unban</a></li><li><a href="module-unbanall.html">unbanall</a></li><li><a href="module-whisper.html">whisper</a></li></ul>
</nav>
<br class="clear">
<footer>
Documentation generated by <a href="https://github.com/jsdoc/jsdoc">JSDoc 3.6.6</a> on Wed Jun 22 2022 10:04:25 GMT-0500 (Central Daylight Time)
</footer>
<script> prettyPrint(); </script>
<script src="scripts/linenumber.js"> </script>
</body>
</html>

View File

@ -0,0 +1,250 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>JSDoc: Source: mod/forcecolor.js</title>
<script src="scripts/prettify/prettify.js"> </script>
<script src="scripts/prettify/lang-css.js"> </script>
<!--[if lt IE 9]>
<script src="//html5shiv.googlecode.com/svn/trunk/html5.js"></script>
<![endif]-->
<link type="text/css" rel="stylesheet" href="styles/prettify-tomorrow.css">
<link type="text/css" rel="stylesheet" href="styles/jsdoc-default.css">
</head>
<body>
<div id="main">
<h1 class="page-title">Source: mod/forcecolor.js</h1>
<section>
<article>
<pre class="prettyprint source linenums"><code>/**
* @author Marzavec ( https://github.com/marzavec )
* @summary Color a user
* @version 1.0.0
* @description Forces a user nick to become a certain color
* @module forcecolor
*/
import {
isModerator,
getUserDetails,
} from '../utility/_UAC.js';
import {
Errors,
} from '../utility/_Constants.js';
import {
findUser,
} from '../utility/_Channels.js';
/**
* Validate a string as a valid hex color string
* @param {string} color - Color string to validate
* @private
* @todo Move into utility module
* @return {boolean}
*/
const verifyColor = (color) => /(^[0-9A-F]{6}$)|(^[0-9A-F]{3}$)/i.test(color);
/**
* Executes when invoked by a remote client
* @param {Object} env - Enviroment object with references to core, server, socket &amp; payload
* @public
* @return {void}
*/
export async function run({
server, socket, payload,
}) {
// increase rate limit chance and ignore if not admin or mod
if (!isModerator(socket.level)) {
return server.police.frisk(socket.address, 10);
}
const { channel } = socket;
if (typeof payload.channel === 'undefined') {
payload.channel = channel;
}
// check user input
if (typeof payload.nick !== 'string') {
return true;
}
if (typeof payload.color !== 'string') {
return true;
}
// make sure requested nickname meets standards
const newColor = payload.color.trim().toUpperCase().replace(/#/g, '');
if (newColor !== 'RESET' &amp;&amp; !verifyColor(newColor)) {
return server.reply({
cmd: 'warn',
text: 'Invalid color! Color must be in hex value',
channel, // @todo Multichannel
}, socket);
}
// find target user
const targetUser = findUser(server, payload);
if (!targetUser) {
return server.reply({
cmd: 'warn',
text: 'Could not find user in that channel',
id: Errors.Global.UNKNOWN_USER,
channel: socket.channel, // @todo Multichannel
}, socket);
}
// TODO: Change this uType to use level / uac
// i guess coloring mods or admins isn't the best idea?
if (targetUser.uType !== 'user') {
return true;
}
if (newColor === 'RESET') {
targetUser.color = false;
} else {
targetUser.color = newColor;
}
// build update notice with new color
const updateNotice = {
...getUserDetails(targetUser),
...{
cmd: 'updateUser',
channel: socket.channel, // @todo Multichannel
},
};
// notify channel that the user has changed their name
// @todo this should be sent to every channel the user is in (multichannel)
server.broadcast(updateNotice, { channel: socket.channel });
return true;
}
/**
* Automatically executes once after server is ready to register this modules hooks
* @param {Object} server - Reference to server enviroment object
* @public
* @return {void}
*/
export function initHooks(server) {
server.registerHook('in', 'chat', this.colorCheck.bind(this), 20);
}
/**
* Executes every time an incoming chat command is invoked;
* hooks chat commands checking for /forcecolor
* @param {Object} env - Enviroment object with references to core, server, socket &amp; payload
* @public
* @return {{Object|boolean|string}} Object = same/altered payload,
* false = suppress action,
* string = error
*/
export function colorCheck({
core, server, socket, payload,
}) {
if (typeof payload.text !== 'string') {
return false;
}
if (payload.text.startsWith('/forcecolor ')) {
const input = payload.text.split(' ');
// If there is no nickname target parameter
if (input[1] === undefined) {
server.reply({
cmd: 'warn',
text: 'Refer to `/help forcecolor` for instructions on how to use this command.',
channel: socket.channel, // @todo Multichannel
}, socket);
return false;
}
if (input[2] === undefined) {
server.reply({
cmd: 'warn',
text: 'Refer to `/help forcecolor` for instructions on how to use this command.',
channel: socket.channel, // @todo Multichannel
}, socket);
return false;
}
const target = input[1].replace(/@/g, '');
this.run({
core,
server,
socket,
payload: {
cmd: 'forcecolor',
nick: target,
color: input[2],
},
});
return false;
}
return payload;
}
/**
* The following payload properties are required to invoke this module:
* "nick", "color"
* @public
* @typedef {Array} forcecolor/requiredData
*/
export const requiredData = ['nick', 'color'];
/**
* Module meta information
* @public
* @typedef {Object} forcecolor/info
* @property {string} name - Module command name
* @property {string} category - Module category name
* @property {string} description - Information about module
* @property {string} usage - Information about module usage
*/
export const info = {
name: 'forcecolor',
category: 'moderators',
description: 'Forces a user nick to become a certain color',
usage: `
API: { cmd: 'forcecolor', nick: '&lt;target nick>', color: '&lt;color as hex>' }
Text: /forcecolor &lt;target nick> &lt;color as hex>`,
};
</code></pre>
</article>
</section>
</div>
<nav>
<h2><a href="index.html">Home</a></h2><h3>Modules</h3><ul><li><a href="module-addmod.html">addmod</a></li><li><a href="module-ban.html">ban</a></li><li><a href="module-changecolor.html">changecolor</a></li><li><a href="module-changenick.html">changenick</a></li><li><a href="module-chat.html">chat</a></li><li><a href="module-disconnect.html">disconnect</a></li><li><a href="module-dumb.html">dumb</a></li><li><a href="module-emote.html">emote</a></li><li><a href="module-forcecolor.html">forcecolor</a></li><li><a href="module-help.html">help</a></li><li><a href="module-invite.html">invite</a></li><li><a href="module-join.html">join</a></li><li><a href="module-kick.html">kick</a></li><li><a href="module-listusers.html">listusers</a></li><li><a href="module-morestats.html">morestats</a></li><li><a href="module-ping.html">ping</a></li><li><a href="module-reload.html">reload</a></li><li><a href="module-removemod.html">removemod</a></li><li><a href="module-saveconfig.html">saveconfig</a></li><li><a href="module-session.html">session</a></li><li><a href="module-shout.html">shout</a></li><li><a href="module-socketreply.html">socketreply</a></li><li><a href="module-speak.html">speak</a></li><li><a href="module-stats.html">stats</a></li><li><a href="module-unban.html">unban</a></li><li><a href="module-unbanall.html">unbanall</a></li><li><a href="module-whisper.html">whisper</a></li></ul>
</nav>
<br class="clear">
<footer>
Documentation generated by <a href="https://github.com/jsdoc/jsdoc">JSDoc 3.6.6</a> on Wed Jun 22 2022 10:04:25 GMT-0500 (Central Daylight Time)
</footer>
<script> prettyPrint(); </script>
<script src="scripts/linenumber.js"> </script>
</body>
</html>

View File

@ -0,0 +1,203 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>JSDoc: Source: mod/kick.js</title>
<script src="scripts/prettify/prettify.js"> </script>
<script src="scripts/prettify/lang-css.js"> </script>
<!--[if lt IE 9]>
<script src="//html5shiv.googlecode.com/svn/trunk/html5.js"></script>
<![endif]-->
<link type="text/css" rel="stylesheet" href="styles/prettify-tomorrow.css">
<link type="text/css" rel="stylesheet" href="styles/jsdoc-default.css">
</head>
<body>
<div id="main">
<h1 class="page-title">Source: mod/kick.js</h1>
<section>
<article>
<pre class="prettyprint source linenums"><code>/**
* @author Marzavec ( https://github.com/marzavec )
* @summary Give da boot
* @version 1.0.0
* @description Silently forces target client(s) into another channel
* @module kick
*/
import {
isModerator,
levels,
getUserDetails,
} from '../utility/_UAC.js';
import {
Errors,
} from '../utility/_Constants.js';
import {
findUsers,
} from '../utility/_Channels.js';
/**
* Executes when invoked by a remote client
* @param {Object} env - Enviroment object with references to core, server, socket &amp; payload
* @public
* @return {void}
*/
export async function run({
core, server, socket, payload,
}) {
// increase rate limit chance and ignore if not admin or mod
if (!isModerator(socket.level)) {
return server.police.frisk(socket.address, 10);
}
// check user input
if (socket.hcProtocol === 1) {
if (typeof payload.nick !== 'string') {
if (typeof payload.nick !== 'object' &amp;&amp; !Array.isArray(payload.nick)) {
return true;
}
}
payload.channel = socket.channel; // eslint-disable-line no-param-reassign
} else if (typeof payload.userid !== 'number') {
// @todo create multi-ban ui
if (typeof payload.userid !== 'object' &amp;&amp; !Array.isArray(payload.userid)) {
return true;
}
}
// find target user(s)
const badClients = findUsers(server, payload);
if (badClients.length === 0) {
return server.reply({
cmd: 'warn',
text: 'Could not find user(s) in that channel',
id: Errors.Global.UNKNOWN_USER,
channel: socket.channel, // @todo Multichannel
}, socket);
}
// check if found targets are kickable, add them to the list if they are
const kicked = [];
for (let i = 0, j = badClients.length; i &lt; j; i += 1) {
if (badClients[i].level >= socket.level) {
server.reply({
cmd: 'warn',
text: 'Cannot kick other users with the same level, how rude',
id: Errors.Global.PERMISSION,
channel: socket.channel, // @todo Multichannel
}, socket);
} else {
kicked.push(badClients[i]);
}
}
if (kicked.length === 0) {
return true;
}
let destChannel;
if (typeof payload.to === 'string' &amp;&amp; !!payload.to.trim()) {
destChannel = payload.to;
} else {
destChannel = Math.random().toString(36).substr(2, 8);
}
// Announce the kicked clients arrival in destChannel and that they were kicked
// Before they arrive, so they don't see they got moved
for (let i = 0; i &lt; kicked.length; i += 1) {
server.broadcast({
...getUserDetails(kicked[i]),
...{
cmd: 'onlineAdd',
channel: destChannel, // @todo Multichannel
},
}, { channel: destChannel });
}
// Move all kicked clients to the new channel
for (let i = 0; i &lt; kicked.length; i += 1) {
// @todo multi-channel update
kicked[i].channel = destChannel;
server.broadcast({
cmd: 'info',
text: `${kicked[i].nick} was banished to ?${destChannel}`,
channel: socket.channel, // @todo Multichannel
}, { channel: socket.channel, level: isModerator });
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 &lt; j; i += 1) {
server.broadcast({
cmd: 'onlineRemove',
userid: kicked[i].userid,
nick: kicked[i].nick,
channel: socket.channel, // @todo Multichannel
}, { channel: socket.channel });
}
// publicly broadcast kick event
server.broadcast({
cmd: 'info',
text: `Kicked ${kicked.map((k) => k.nick).join(', ')}`,
channel: socket.channel, // @todo Multichannel
}, { channel: socket.channel, level: (level) => level &lt; levels.moderator });
// stats are fun
core.stats.increment('users-kicked', kicked.length);
return true;
}
/**
* Module meta information
* @public
* @typedef {Object} kick/info
* @property {string} name - Module command name
* @property {string} category - Module category name
* @property {string} description - Information about module
* @property {string} usage - Information about module usage
*/
export const info = {
name: 'kick',
category: 'moderators',
description: 'Silently forces target client(s) into another channel. `nick` may be string or array of strings',
usage: `
API: { cmd: 'kick', nick: '&lt;target nick>', to: '&lt;optional target channel>' }`,
};
</code></pre>
</article>
</section>
</div>
<nav>
<h2><a href="index.html">Home</a></h2><h3>Modules</h3><ul><li><a href="module-addmod.html">addmod</a></li><li><a href="module-ban.html">ban</a></li><li><a href="module-changecolor.html">changecolor</a></li><li><a href="module-changenick.html">changenick</a></li><li><a href="module-chat.html">chat</a></li><li><a href="module-disconnect.html">disconnect</a></li><li><a href="module-dumb.html">dumb</a></li><li><a href="module-emote.html">emote</a></li><li><a href="module-forcecolor.html">forcecolor</a></li><li><a href="module-help.html">help</a></li><li><a href="module-invite.html">invite</a></li><li><a href="module-join.html">join</a></li><li><a href="module-kick.html">kick</a></li><li><a href="module-listusers.html">listusers</a></li><li><a href="module-morestats.html">morestats</a></li><li><a href="module-ping.html">ping</a></li><li><a href="module-reload.html">reload</a></li><li><a href="module-removemod.html">removemod</a></li><li><a href="module-saveconfig.html">saveconfig</a></li><li><a href="module-session.html">session</a></li><li><a href="module-shout.html">shout</a></li><li><a href="module-socketreply.html">socketreply</a></li><li><a href="module-speak.html">speak</a></li><li><a href="module-stats.html">stats</a></li><li><a href="module-unban.html">unban</a></li><li><a href="module-unbanall.html">unbanall</a></li><li><a href="module-whisper.html">whisper</a></li></ul>
</nav>
<br class="clear">
<footer>
Documentation generated by <a href="https://github.com/jsdoc/jsdoc">JSDoc 3.6.6</a> on Wed Jun 22 2022 10:04:25 GMT-0500 (Central Daylight Time)
</footer>
<script> prettyPrint(); </script>
<script src="scripts/linenumber.js"> </script>
</body>
</html>

View File

@ -0,0 +1,157 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>JSDoc: Source: mod/speak.js</title>
<script src="scripts/prettify/prettify.js"> </script>
<script src="scripts/prettify/lang-css.js"> </script>
<!--[if lt IE 9]>
<script src="//html5shiv.googlecode.com/svn/trunk/html5.js"></script>
<![endif]-->
<link type="text/css" rel="stylesheet" href="styles/prettify-tomorrow.css">
<link type="text/css" rel="stylesheet" href="styles/jsdoc-default.css">
</head>
<body>
<div id="main">
<h1 class="page-title">Source: mod/speak.js</h1>
<section>
<article>
<pre class="prettyprint source linenums"><code>/* eslint no-param-reassign: 0 */
/**
* @author OpSimple ( https://github.com/OpSimple )
* @summary Unmuzzle a user
* @version 1.0.0
* @description Pardon a dumb user to be able to speak again
* @module speak
*/
import {
isModerator,
} from '../utility/_UAC.js';
/**
* Automatically executes once after server is ready
* @param {Object} core - Reference to core enviroment object
* @public
* @return {void}
*/
export function init(core) {
if (typeof core.muzzledHashes === 'undefined') {
core.muzzledHashes = {};
}
}
/**
* Executes when invoked by a remote client
* @param {Object} env - Enviroment object with references to core, server, socket &amp; payload
* @public
* @return {void}
*/
export async function run({
core, server, socket, payload,
}) {
// increase rate limit chance and ignore if not admin or mod
if (!isModerator(socket.level)) {
return server.police.frisk(socket.address, 10);
}
// check user input
if (typeof payload.ip !== 'string' &amp;&amp; typeof payload.hash !== 'string') {
return server.reply({
cmd: 'warn', // @todo Add numeric error code as `id`
text: "hash:'targethash' or ip:'1.2.3.4' is required",
channel: socket.channel, // @todo Multichannel
}, socket);
}
if (typeof payload.ip === 'string') {
if (payload.ip === '*') {
core.muzzledHashes = {};
return server.broadcast({
cmd: 'info',
text: `${socket.nick} unmuzzled all users`,
channel: false, // @todo Multichannel, false for global
}, { level: isModerator });
}
} else if (payload.hash === '*') {
core.muzzledHashes = {};
return server.broadcast({
cmd: 'info',
text: `${socket.nick} unmuzzled all users`,
channel: false, // @todo Multichannel, false for global
}, { level: isModerator });
}
// find target &amp; remove mute status
let target;
if (typeof payload.ip === 'string') {
target = server.getSocketHash(payload.ip);
} else {
target = payload.hash;
}
delete core.muzzledHashes[target];
// notify mods
server.broadcast({
cmd: 'info',
text: `${socket.nick}#${socket.trip} unmuzzled : ${target}`,
channel: false, // @todo Multichannel, false for global
}, { level: isModerator });
return true;
}
/**
* Module meta information
* @public
* @typedef {Object} speak/info
* @property {string} name - Module command name
* @property {string} category - Module category name
* @property {string} description - Information about module
* @property {string} usage - Information about module usage
*/
export const info = {
name: 'speak',
category: 'moderators',
description: 'Pardon a dumb user to be able to speak again',
aliases: ['unmuzzle', 'unmute'],
usage: `
API: { cmd: 'speak', ip/hash: '&lt;target ip or hash' }`,
};
</code></pre>
</article>
</section>
</div>
<nav>
<h2><a href="index.html">Home</a></h2><h3>Modules</h3><ul><li><a href="module-addmod.html">addmod</a></li><li><a href="module-ban.html">ban</a></li><li><a href="module-changecolor.html">changecolor</a></li><li><a href="module-changenick.html">changenick</a></li><li><a href="module-chat.html">chat</a></li><li><a href="module-disconnect.html">disconnect</a></li><li><a href="module-dumb.html">dumb</a></li><li><a href="module-emote.html">emote</a></li><li><a href="module-forcecolor.html">forcecolor</a></li><li><a href="module-help.html">help</a></li><li><a href="module-invite.html">invite</a></li><li><a href="module-join.html">join</a></li><li><a href="module-kick.html">kick</a></li><li><a href="module-listusers.html">listusers</a></li><li><a href="module-morestats.html">morestats</a></li><li><a href="module-ping.html">ping</a></li><li><a href="module-reload.html">reload</a></li><li><a href="module-removemod.html">removemod</a></li><li><a href="module-saveconfig.html">saveconfig</a></li><li><a href="module-session.html">session</a></li><li><a href="module-shout.html">shout</a></li><li><a href="module-socketreply.html">socketreply</a></li><li><a href="module-speak.html">speak</a></li><li><a href="module-stats.html">stats</a></li><li><a href="module-unban.html">unban</a></li><li><a href="module-unbanall.html">unbanall</a></li><li><a href="module-whisper.html">whisper</a></li></ul>
</nav>
<br class="clear">
<footer>
Documentation generated by <a href="https://github.com/jsdoc/jsdoc">JSDoc 3.6.6</a> on Wed Jun 22 2022 10:04:25 GMT-0500 (Central Daylight Time)
</footer>
<script> prettyPrint(); </script>
<script src="scripts/linenumber.js"> </script>
</body>
</html>

View File

@ -0,0 +1,142 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>JSDoc: Source: mod/unban.js</title>
<script src="scripts/prettify/prettify.js"> </script>
<script src="scripts/prettify/lang-css.js"> </script>
<!--[if lt IE 9]>
<script src="//html5shiv.googlecode.com/svn/trunk/html5.js"></script>
<![endif]-->
<link type="text/css" rel="stylesheet" href="styles/prettify-tomorrow.css">
<link type="text/css" rel="stylesheet" href="styles/jsdoc-default.css">
</head>
<body>
<div id="main">
<h1 class="page-title">Source: mod/unban.js</h1>
<section>
<article>
<pre class="prettyprint source linenums"><code>/**
* @author Marzavec ( https://github.com/marzavec )
* @summary Unban a user
* @version 1.0.0
* @description Un-bans target user by ip or hash
* @module unban
*/
import {
isModerator,
} from '../utility/_UAC.js';
/**
* Executes when invoked by a remote client
* @param {Object} env - Enviroment object with references to core, server, socket &amp; payload
* @public
* @return {void}
*/
export async function run({
core, server, socket, payload,
}) {
// increase rate limit chance and ignore if not admin or mod
if (!isModerator(socket.level)) {
return server.police.frisk(socket.address, 10);
}
// check user input
if (typeof payload.ip !== 'string' &amp;&amp; typeof payload.hash !== 'string') {
return server.reply({
cmd: 'warn', // @todo Add numeric error code as `id`
text: "hash:'targethash' or ip:'1.2.3.4' is required",
channel: socket.channel, // @todo Multichannel
}, socket);
}
// find target
let mode;
let target;
if (typeof payload.ip === 'string') {
mode = 'ip';
target = payload.ip;
} else {
mode = 'hash';
target = payload.hash;
}
// remove arrest record
server.police.pardon(target);
// mask ip if used
if (mode === 'ip') {
target = server.getSocketHash(target);
}
console.log(`${socket.nick} [${socket.trip}] unbanned ${target} in ${socket.channel}`);
// reply with success
server.reply({
cmd: 'info',
text: `Unbanned ${target}`,
channel: socket.channel, // @todo Multichannel
}, socket);
// notify mods
server.broadcast({
cmd: 'info',
text: `${socket.nick}#${socket.trip} unbanned: ${target}`,
channel: false, // @todo Multichannel, false for global
}, { level: isModerator });
// stats are fun
core.stats.decrement('users-banned');
return true;
}
/**
* Module meta information
* @public
* @typedef {Object} unban/info
* @property {string} name - Module command name
* @property {string} category - Module category name
* @property {string} description - Information about module
* @property {string} usage - Information about module usage
*/
export const info = {
name: 'unban',
category: 'moderators',
description: 'Un-bans target user by ip or hash',
usage: `
API: { cmd: 'unban', ip/hash: '&lt;target ip or hash>' }`,
};
</code></pre>
</article>
</section>
</div>
<nav>
<h2><a href="index.html">Home</a></h2><h3>Modules</h3><ul><li><a href="module-addmod.html">addmod</a></li><li><a href="module-ban.html">ban</a></li><li><a href="module-changecolor.html">changecolor</a></li><li><a href="module-changenick.html">changenick</a></li><li><a href="module-chat.html">chat</a></li><li><a href="module-disconnect.html">disconnect</a></li><li><a href="module-dumb.html">dumb</a></li><li><a href="module-emote.html">emote</a></li><li><a href="module-forcecolor.html">forcecolor</a></li><li><a href="module-help.html">help</a></li><li><a href="module-invite.html">invite</a></li><li><a href="module-join.html">join</a></li><li><a href="module-kick.html">kick</a></li><li><a href="module-listusers.html">listusers</a></li><li><a href="module-morestats.html">morestats</a></li><li><a href="module-ping.html">ping</a></li><li><a href="module-reload.html">reload</a></li><li><a href="module-removemod.html">removemod</a></li><li><a href="module-saveconfig.html">saveconfig</a></li><li><a href="module-session.html">session</a></li><li><a href="module-shout.html">shout</a></li><li><a href="module-socketreply.html">socketreply</a></li><li><a href="module-speak.html">speak</a></li><li><a href="module-stats.html">stats</a></li><li><a href="module-unban.html">unban</a></li><li><a href="module-unbanall.html">unbanall</a></li><li><a href="module-whisper.html">whisper</a></li></ul>
</nav>
<br class="clear">
<footer>
Documentation generated by <a href="https://github.com/jsdoc/jsdoc">JSDoc 3.6.6</a> on Wed Jun 22 2022 10:04:25 GMT-0500 (Central Daylight Time)
</footer>
<script> prettyPrint(); </script>
<script src="scripts/linenumber.js"> </script>
</body>
</html>

View File

@ -0,0 +1,115 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>JSDoc: Source: mod/unbanall.js</title>
<script src="scripts/prettify/prettify.js"> </script>
<script src="scripts/prettify/lang-css.js"> </script>
<!--[if lt IE 9]>
<script src="//html5shiv.googlecode.com/svn/trunk/html5.js"></script>
<![endif]-->
<link type="text/css" rel="stylesheet" href="styles/prettify-tomorrow.css">
<link type="text/css" rel="stylesheet" href="styles/jsdoc-default.css">
</head>
<body>
<div id="main">
<h1 class="page-title">Source: mod/unbanall.js</h1>
<section>
<article>
<pre class="prettyprint source linenums"><code>/**
* @author Marzavec ( https://github.com/marzavec )
* @summary Released them from the void
* @version 1.0.0
* @description Clears all banned ip addresses
* @module unbanall
*/
import {
isModerator,
} from '../utility/_UAC.js';
/**
* Executes when invoked by a remote client
* @param {Object} env - Enviroment object with references to core, server, socket &amp; payload
* @public
* @return {void}
*/
export async function run({ core, server, socket }) {
// increase rate limit chance and ignore if not admin or mod
if (!isModerator(socket.level)) {
return server.police.frisk(socket.address, 10);
}
// remove arrest records
server.police.clear();
core.stats.set('users-banned', 0);
console.log(`${socket.nick} [${socket.trip}] unbanned all`);
// reply with success
server.reply({
cmd: 'info',
text: 'Unbanned all ip addresses',
channel: socket.channel, // @todo Multichannel
}, socket);
// notify mods
server.broadcast({
cmd: 'info',
text: `${socket.nick}#${socket.trip} unbanned all ip addresses`,
channel: false, // @todo Multichannel, false for global
}, { level: isModerator });
return true;
}
/**
* Module meta information
* @public
* @typedef {Object} unbanall/info
* @property {string} name - Module command name
* @property {string} category - Module category name
* @property {string} description - Information about module
* @property {string} usage - Information about module usage
*/
export const info = {
name: 'unbanall',
category: 'moderators',
description: 'Clears all banned ip addresses',
usage: `
API: { cmd: 'unbanall' }`,
};
</code></pre>
</article>
</section>
</div>
<nav>
<h2><a href="index.html">Home</a></h2><h3>Modules</h3><ul><li><a href="module-addmod.html">addmod</a></li><li><a href="module-ban.html">ban</a></li><li><a href="module-changecolor.html">changecolor</a></li><li><a href="module-changenick.html">changenick</a></li><li><a href="module-chat.html">chat</a></li><li><a href="module-disconnect.html">disconnect</a></li><li><a href="module-dumb.html">dumb</a></li><li><a href="module-emote.html">emote</a></li><li><a href="module-forcecolor.html">forcecolor</a></li><li><a href="module-help.html">help</a></li><li><a href="module-invite.html">invite</a></li><li><a href="module-join.html">join</a></li><li><a href="module-kick.html">kick</a></li><li><a href="module-listusers.html">listusers</a></li><li><a href="module-morestats.html">morestats</a></li><li><a href="module-ping.html">ping</a></li><li><a href="module-reload.html">reload</a></li><li><a href="module-removemod.html">removemod</a></li><li><a href="module-saveconfig.html">saveconfig</a></li><li><a href="module-session.html">session</a></li><li><a href="module-shout.html">shout</a></li><li><a href="module-socketreply.html">socketreply</a></li><li><a href="module-speak.html">speak</a></li><li><a href="module-stats.html">stats</a></li><li><a href="module-unban.html">unban</a></li><li><a href="module-unbanall.html">unbanall</a></li><li><a href="module-whisper.html">whisper</a></li></ul>
</nav>
<br class="clear">
<footer>
Documentation generated by <a href="https://github.com/jsdoc/jsdoc">JSDoc 3.6.6</a> on Wed Jun 22 2022 10:04:25 GMT-0500 (Central Daylight Time)
</footer>
<script> prettyPrint(); </script>
<script src="scripts/linenumber.js"> </script>
</body>
</html>

View File

@ -0,0 +1,604 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>JSDoc: Module: addmod</title>
<script src="scripts/prettify/prettify.js"> </script>
<script src="scripts/prettify/lang-css.js"> </script>
<!--[if lt IE 9]>
<script src="//html5shiv.googlecode.com/svn/trunk/html5.js"></script>
<![endif]-->
<link type="text/css" rel="stylesheet" href="styles/prettify-tomorrow.css">
<link type="text/css" rel="stylesheet" href="styles/jsdoc-default.css">
</head>
<body>
<div id="main">
<h1 class="page-title">Module: addmod</h1>
<section>
<header>
</header>
<article>
<div class="container-overview">
<div class="description">Adds target trip to the config as a mod and upgrades the socket type</div>
<dl class="details">
<dt class="tag-version">Version:</dt>
<dd class="tag-version"><ul class="dummy"><li>1.0.0</li></ul></dd>
<dt class="tag-author">Author:</dt>
<dd class="tag-author">
<ul>
<li>Marzavec ( https://github.com/marzavec )</li>
</ul>
</dd>
<dt class="tag-source">Source:</dt>
<dd class="tag-source"><ul class="dummy"><li>
<a href="admin_addmod.js.html">admin/addmod.js</a>, <a href="admin_addmod.js.html#line1">line 1</a>
</li></ul></dd>
</dl>
</div>
<h3 class="subsection-title">Methods</h3>
<h4 class="name" id=".run"><span class="type-signature">(static) </span>run<span class="signature">(env)</span><span class="type-signature"> &rarr; {void}</span></h4>
<div class="description">
Executes when invoked by a remote client
</div>
<h5>Parameters:</h5>
<table class="params">
<thead>
<tr>
<th>Name</th>
<th>Type</th>
<th class="last">Description</th>
</tr>
</thead>
<tbody>
<tr>
<td class="name"><code>env</code></td>
<td class="type">
<span class="param-type">Object</span>
</td>
<td class="description last">Enviroment object with references to core, server, socket & payload</td>
</tr>
</tbody>
</table>
<dl class="details">
<dt class="tag-source">Source:</dt>
<dd class="tag-source"><ul class="dummy"><li>
<a href="admin_addmod.js.html">admin/addmod.js</a>, <a href="admin_addmod.js.html#line22">line 22</a>
</li></ul></dd>
</dl>
<h5>Returns:</h5>
<dl>
<dt>
Type
</dt>
<dd>
<span class="param-type">void</span>
</dd>
</dl>
<h3 class="subsection-title">Type Definitions</h3>
<h4 class="name" id="~addmod/info">addmod/info</h4>
<div class="description">
Module meta information
</div>
<h5>Type:</h5>
<ul>
<li>
<span class="param-type">Object</span>
</li>
</ul>
<h5 class="subsection-title">Properties:</h5>
<table class="props">
<thead>
<tr>
<th>Name</th>
<th>Type</th>
<th class="last">Description</th>
</tr>
</thead>
<tbody>
<tr>
<td class="name"><code>name</code></td>
<td class="type">
<span class="param-type">string</span>
</td>
<td class="description last">Module command name</td>
</tr>
<tr>
<td class="name"><code>category</code></td>
<td class="type">
<span class="param-type">string</span>
</td>
<td class="description last">Module category name</td>
</tr>
<tr>
<td class="name"><code>description</code></td>
<td class="type">
<span class="param-type">string</span>
</td>
<td class="description last">Information about module</td>
</tr>
<tr>
<td class="name"><code>usage</code></td>
<td class="type">
<span class="param-type">string</span>
</td>
<td class="description last">Information about module usage</td>
</tr>
</tbody>
</table>
<dl class="details">
<dt class="tag-source">Source:</dt>
<dd class="tag-source"><ul class="dummy"><li>
<a href="admin_addmod.js.html">admin/addmod.js</a>, <a href="admin_addmod.js.html#line93">line 93</a>
</li></ul></dd>
</dl>
<h4 class="name" id="~addmod/requiredData">addmod/requiredData</h4>
<div class="description">
The following payload properties are required to invoke this module:
"trip"
</div>
<h5>Type:</h5>
<ul>
<li>
<span class="param-type">Array</span>
</li>
</ul>
<dl class="details">
<dt class="tag-source">Source:</dt>
<dd class="tag-source"><ul class="dummy"><li>
<a href="admin_addmod.js.html">admin/addmod.js</a>, <a href="admin_addmod.js.html#line85">line 85</a>
</li></ul></dd>
</dl>
</article>
</section>
</div>
<nav>
<h2><a href="index.html">Home</a></h2><h3>Modules</h3><ul><li><a href="module-addmod.html">addmod</a></li><li><a href="module-ban.html">ban</a></li><li><a href="module-changecolor.html">changecolor</a></li><li><a href="module-changenick.html">changenick</a></li><li><a href="module-chat.html">chat</a></li><li><a href="module-disconnect.html">disconnect</a></li><li><a href="module-dumb.html">dumb</a></li><li><a href="module-emote.html">emote</a></li><li><a href="module-forcecolor.html">forcecolor</a></li><li><a href="module-help.html">help</a></li><li><a href="module-invite.html">invite</a></li><li><a href="module-join.html">join</a></li><li><a href="module-kick.html">kick</a></li><li><a href="module-listusers.html">listusers</a></li><li><a href="module-morestats.html">morestats</a></li><li><a href="module-ping.html">ping</a></li><li><a href="module-reload.html">reload</a></li><li><a href="module-removemod.html">removemod</a></li><li><a href="module-saveconfig.html">saveconfig</a></li><li><a href="module-session.html">session</a></li><li><a href="module-shout.html">shout</a></li><li><a href="module-socketreply.html">socketreply</a></li><li><a href="module-speak.html">speak</a></li><li><a href="module-stats.html">stats</a></li><li><a href="module-unban.html">unban</a></li><li><a href="module-unbanall.html">unbanall</a></li><li><a href="module-whisper.html">whisper</a></li></ul>
</nav>
<br class="clear">
<footer>
Documentation generated by <a href="https://github.com/jsdoc/jsdoc">JSDoc 3.6.6</a> on Wed Jun 22 2022 10:04:25 GMT-0500 (Central Daylight Time)
</footer>
<script> prettyPrint(); </script>
<script src="scripts/linenumber.js"> </script>
</body>
</html>

View File

@ -0,0 +1,531 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>JSDoc: Module: ban</title>
<script src="scripts/prettify/prettify.js"> </script>
<script src="scripts/prettify/lang-css.js"> </script>
<!--[if lt IE 9]>
<script src="//html5shiv.googlecode.com/svn/trunk/html5.js"></script>
<![endif]-->
<link type="text/css" rel="stylesheet" href="styles/prettify-tomorrow.css">
<link type="text/css" rel="stylesheet" href="styles/jsdoc-default.css">
</head>
<body>
<div id="main">
<h1 class="page-title">Module: ban</h1>
<section>
<header>
</header>
<article>
<div class="container-overview">
<div class="description">Bans target user by name</div>
<dl class="details">
<dt class="tag-version">Version:</dt>
<dd class="tag-version"><ul class="dummy"><li>1.0.0</li></ul></dd>
<dt class="tag-author">Author:</dt>
<dd class="tag-author">
<ul>
<li>Marzavec ( https://github.com/marzavec )</li>
</ul>
</dd>
<dt class="tag-source">Source:</dt>
<dd class="tag-source"><ul class="dummy"><li>
<a href="mod_ban.js.html">mod/ban.js</a>, <a href="mod_ban.js.html#line1">line 1</a>
</li></ul></dd>
</dl>
</div>
<h3 class="subsection-title">Methods</h3>
<h4 class="name" id=".run"><span class="type-signature">(static) </span>run<span class="signature">(env)</span><span class="type-signature"> &rarr; {void}</span></h4>
<div class="description">
Executes when invoked by a remote client
</div>
<h5>Parameters:</h5>
<table class="params">
<thead>
<tr>
<th>Name</th>
<th>Type</th>
<th class="last">Description</th>
</tr>
</thead>
<tbody>
<tr>
<td class="name"><code>env</code></td>
<td class="type">
<span class="param-type">Object</span>
</td>
<td class="description last">Enviroment object with references to core, server, socket & payload</td>
</tr>
</tbody>
</table>
<dl class="details">
<dt class="tag-source">Source:</dt>
<dd class="tag-source"><ul class="dummy"><li>
<a href="mod_ban.js.html">mod/ban.js</a>, <a href="mod_ban.js.html#line27">line 27</a>
</li></ul></dd>
</dl>
<h5>Returns:</h5>
<dl>
<dt>
Type
</dt>
<dd>
<span class="param-type">void</span>
</dd>
</dl>
<h3 class="subsection-title">Type Definitions</h3>
<h4 class="name" id="~ban/info">ban/info</h4>
<div class="description">
Module meta information
</div>
<h5>Type:</h5>
<ul>
<li>
<span class="param-type">Object</span>
</li>
</ul>
<h5 class="subsection-title">Properties:</h5>
<table class="props">
<thead>
<tr>
<th>Name</th>
<th>Type</th>
<th class="last">Description</th>
</tr>
</thead>
<tbody>
<tr>
<td class="name"><code>name</code></td>
<td class="type">
<span class="param-type">string</span>
</td>
<td class="description last">Module command name</td>
</tr>
<tr>
<td class="name"><code>category</code></td>
<td class="type">
<span class="param-type">string</span>
</td>
<td class="description last">Module category name</td>
</tr>
<tr>
<td class="name"><code>description</code></td>
<td class="type">
<span class="param-type">string</span>
</td>
<td class="description last">Information about module</td>
</tr>
<tr>
<td class="name"><code>usage</code></td>
<td class="type">
<span class="param-type">string</span>
</td>
<td class="description last">Information about module usage</td>
</tr>
</tbody>
</table>
<dl class="details">
<dt class="tag-source">Source:</dt>
<dd class="tag-source"><ul class="dummy"><li>
<a href="mod_ban.js.html">mod/ban.js</a>, <a href="mod_ban.js.html#line100">line 100</a>
</li></ul></dd>
</dl>
</article>
</section>
</div>
<nav>
<h2><a href="index.html">Home</a></h2><h3>Modules</h3><ul><li><a href="module-addmod.html">addmod</a></li><li><a href="module-ban.html">ban</a></li><li><a href="module-changecolor.html">changecolor</a></li><li><a href="module-changenick.html">changenick</a></li><li><a href="module-chat.html">chat</a></li><li><a href="module-disconnect.html">disconnect</a></li><li><a href="module-dumb.html">dumb</a></li><li><a href="module-emote.html">emote</a></li><li><a href="module-forcecolor.html">forcecolor</a></li><li><a href="module-help.html">help</a></li><li><a href="module-invite.html">invite</a></li><li><a href="module-join.html">join</a></li><li><a href="module-kick.html">kick</a></li><li><a href="module-listusers.html">listusers</a></li><li><a href="module-morestats.html">morestats</a></li><li><a href="module-ping.html">ping</a></li><li><a href="module-reload.html">reload</a></li><li><a href="module-removemod.html">removemod</a></li><li><a href="module-saveconfig.html">saveconfig</a></li><li><a href="module-session.html">session</a></li><li><a href="module-shout.html">shout</a></li><li><a href="module-socketreply.html">socketreply</a></li><li><a href="module-speak.html">speak</a></li><li><a href="module-stats.html">stats</a></li><li><a href="module-unban.html">unban</a></li><li><a href="module-unbanall.html">unbanall</a></li><li><a href="module-whisper.html">whisper</a></li></ul>
</nav>
<br class="clear">
<footer>
Documentation generated by <a href="https://github.com/jsdoc/jsdoc">JSDoc 3.6.6</a> on Wed Jun 22 2022 10:04:25 GMT-0500 (Central Daylight Time)
</footer>
<script> prettyPrint(); </script>
<script src="scripts/linenumber.js"> </script>
</body>
</html>

View File

@ -0,0 +1,902 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>JSDoc: Module: changecolor</title>
<script src="scripts/prettify/prettify.js"> </script>
<script src="scripts/prettify/lang-css.js"> </script>
<!--[if lt IE 9]>
<script src="//html5shiv.googlecode.com/svn/trunk/html5.js"></script>
<![endif]-->
<link type="text/css" rel="stylesheet" href="styles/prettify-tomorrow.css">
<link type="text/css" rel="stylesheet" href="styles/jsdoc-default.css">
</head>
<body>
<div id="main">
<h1 class="page-title">Module: changecolor</h1>
<section>
<header>
</header>
<article>
<div class="container-overview">
<div class="description">Allows calling client to change their nickname color</div>
<dl class="details">
<dt class="tag-version">Version:</dt>
<dd class="tag-version"><ul class="dummy"><li>1.0.0</li></ul></dd>
<dt class="tag-author">Author:</dt>
<dd class="tag-author">
<ul>
<li>Marzavec ( https://github.com/marzavec )</li>
</ul>
</dd>
<dt class="tag-source">Source:</dt>
<dd class="tag-source"><ul class="dummy"><li>
<a href="core_changecolor.js.html">core/changecolor.js</a>, <a href="core_changecolor.js.html#line1">line 1</a>
</li></ul></dd>
</dl>
</div>
<h3 class="subsection-title">Methods</h3>
<h4 class="name" id=".colorCheck"><span class="type-signature">(static) </span>colorCheck<span class="signature">(env)</span><span class="type-signature"></span></h4>
<div class="description">
Executes every time an incoming chat command is invoked
</div>
<h5>Parameters:</h5>
<table class="params">
<thead>
<tr>
<th>Name</th>
<th>Type</th>
<th class="last">Description</th>
</tr>
</thead>
<tbody>
<tr>
<td class="name"><code>env</code></td>
<td class="type">
<span class="param-type">Object</span>
</td>
<td class="description last">Enviroment object with references to core, server, socket & payload</td>
</tr>
</tbody>
</table>
<dl class="details">
<dt class="tag-source">Source:</dt>
<dd class="tag-source"><ul class="dummy"><li>
<a href="core_changecolor.js.html">core/changecolor.js</a>, <a href="core_changecolor.js.html#line96">line 96</a>
</li></ul></dd>
</dl>
<h5>Returns:</h5>
<h4 class="name" id=".initHooks"><span class="type-signature">(static) </span>initHooks<span class="signature">(server)</span><span class="type-signature"> &rarr; {void}</span></h4>
<div class="description">
Automatically executes once after server is ready to register this modules hooks
</div>
<h5>Parameters:</h5>
<table class="params">
<thead>
<tr>
<th>Name</th>
<th>Type</th>
<th class="last">Description</th>
</tr>
</thead>
<tbody>
<tr>
<td class="name"><code>server</code></td>
<td class="type">
<span class="param-type">Object</span>
</td>
<td class="description last">Reference to server enviroment object</td>
</tr>
</tbody>
</table>
<dl class="details">
<dt class="tag-source">Source:</dt>
<dd class="tag-source"><ul class="dummy"><li>
<a href="core_changecolor.js.html">core/changecolor.js</a>, <a href="core_changecolor.js.html#line84">line 84</a>
</li></ul></dd>
</dl>
<h5>Returns:</h5>
<dl>
<dt>
Type
</dt>
<dd>
<span class="param-type">void</span>
</dd>
</dl>
<h4 class="name" id=".run"><span class="type-signature">(static) </span>run<span class="signature">(env)</span><span class="type-signature"> &rarr; {void}</span></h4>
<div class="description">
Executes when invoked by a remote client
</div>
<h5>Parameters:</h5>
<table class="params">
<thead>
<tr>
<th>Name</th>
<th>Type</th>
<th class="last">Description</th>
</tr>
</thead>
<tbody>
<tr>
<td class="name"><code>env</code></td>
<td class="type">
<span class="param-type">Object</span>
</td>
<td class="description last">Enviroment object with references to core, server, socket & payload</td>
</tr>
</tbody>
</table>
<dl class="details">
<dt class="tag-source">Source:</dt>
<dd class="tag-source"><ul class="dummy"><li>
<a href="core_changecolor.js.html">core/changecolor.js</a>, <a href="core_changecolor.js.html#line28">line 28</a>
</li></ul></dd>
</dl>
<h5>Returns:</h5>
<dl>
<dt>
Type
</dt>
<dd>
<span class="param-type">void</span>
</dd>
</dl>
<h3 class="subsection-title">Type Definitions</h3>
<h4 class="name" id="~changecolor/info">changecolor/info</h4>
<div class="description">
Module meta information
</div>
<h5>Type:</h5>
<ul>
<li>
<span class="param-type">Object</span>
</li>
</ul>
<h5 class="subsection-title">Properties:</h5>
<table class="props">
<thead>
<tr>
<th>Name</th>
<th>Type</th>
<th class="last">Description</th>
</tr>
</thead>
<tbody>
<tr>
<td class="name"><code>name</code></td>
<td class="type">
<span class="param-type">string</span>
</td>
<td class="description last">Module command name</td>
</tr>
<tr>
<td class="name"><code>category</code></td>
<td class="type">
<span class="param-type">string</span>
</td>
<td class="description last">Module category name</td>
</tr>
<tr>
<td class="name"><code>description</code></td>
<td class="type">
<span class="param-type">string</span>
</td>
<td class="description last">Information about module</td>
</tr>
<tr>
<td class="name"><code>usage</code></td>
<td class="type">
<span class="param-type">string</span>
</td>
<td class="description last">Information about module usage</td>
</tr>
</tbody>
</table>
<dl class="details">
<dt class="tag-source">Source:</dt>
<dd class="tag-source"><ul class="dummy"><li>
<a href="core_changecolor.js.html">core/changecolor.js</a>, <a href="core_changecolor.js.html#line141">line 141</a>
</li></ul></dd>
</dl>
<h4 class="name" id="~changecolor/requiredData">changecolor/requiredData</h4>
<div class="description">
The following payload properties are required to invoke this module:
"color"
</div>
<h5>Type:</h5>
<ul>
<li>
<span class="param-type">Array</span>
</li>
</ul>
<dl class="details">
<dt class="tag-source">Source:</dt>
<dd class="tag-source"><ul class="dummy"><li>
<a href="core_changecolor.js.html">core/changecolor.js</a>, <a href="core_changecolor.js.html#line133">line 133</a>
</li></ul></dd>
</dl>
</article>
</section>
</div>
<nav>
<h2><a href="index.html">Home</a></h2><h3>Modules</h3><ul><li><a href="module-addmod.html">addmod</a></li><li><a href="module-ban.html">ban</a></li><li><a href="module-changecolor.html">changecolor</a></li><li><a href="module-changenick.html">changenick</a></li><li><a href="module-chat.html">chat</a></li><li><a href="module-disconnect.html">disconnect</a></li><li><a href="module-dumb.html">dumb</a></li><li><a href="module-emote.html">emote</a></li><li><a href="module-forcecolor.html">forcecolor</a></li><li><a href="module-help.html">help</a></li><li><a href="module-invite.html">invite</a></li><li><a href="module-join.html">join</a></li><li><a href="module-kick.html">kick</a></li><li><a href="module-listusers.html">listusers</a></li><li><a href="module-morestats.html">morestats</a></li><li><a href="module-ping.html">ping</a></li><li><a href="module-reload.html">reload</a></li><li><a href="module-removemod.html">removemod</a></li><li><a href="module-saveconfig.html">saveconfig</a></li><li><a href="module-session.html">session</a></li><li><a href="module-shout.html">shout</a></li><li><a href="module-socketreply.html">socketreply</a></li><li><a href="module-speak.html">speak</a></li><li><a href="module-stats.html">stats</a></li><li><a href="module-unban.html">unban</a></li><li><a href="module-unbanall.html">unbanall</a></li><li><a href="module-whisper.html">whisper</a></li></ul>
</nav>
<br class="clear">
<footer>
Documentation generated by <a href="https://github.com/jsdoc/jsdoc">JSDoc 3.6.6</a> on Wed Jun 22 2022 10:04:25 GMT-0500 (Central Daylight Time)
</footer>
<script> prettyPrint(); </script>
<script src="scripts/linenumber.js"> </script>
</body>
</html>

View File

@ -0,0 +1,902 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>JSDoc: Module: changenick</title>
<script src="scripts/prettify/prettify.js"> </script>
<script src="scripts/prettify/lang-css.js"> </script>
<!--[if lt IE 9]>
<script src="//html5shiv.googlecode.com/svn/trunk/html5.js"></script>
<![endif]-->
<link type="text/css" rel="stylesheet" href="styles/prettify-tomorrow.css">
<link type="text/css" rel="stylesheet" href="styles/jsdoc-default.css">
</head>
<body>
<div id="main">
<h1 class="page-title">Module: changenick</h1>
<section>
<header>
</header>
<article>
<div class="container-overview">
<div class="description">Allows calling client to change their current nickname</div>
<dl class="details">
<dt class="tag-version">Version:</dt>
<dd class="tag-version"><ul class="dummy"><li>1.0.0</li></ul></dd>
<dt class="tag-author">Author:</dt>
<dd class="tag-author">
<ul>
<li>Marzavec ( https://github.com/marzavec )</li>
</ul>
</dd>
<dt class="tag-source">Source:</dt>
<dd class="tag-source"><ul class="dummy"><li>
<a href="core_changenick.js.html">core/changenick.js</a>, <a href="core_changenick.js.html#line3">line 3</a>
</li></ul></dd>
</dl>
</div>
<h3 class="subsection-title">Methods</h3>
<h4 class="name" id=".initHooks"><span class="type-signature">(static) </span>initHooks<span class="signature">(server)</span><span class="type-signature"> &rarr; {void}</span></h4>
<div class="description">
Automatically executes once after server is ready to register this modules hooks
</div>
<h5>Parameters:</h5>
<table class="params">
<thead>
<tr>
<th>Name</th>
<th>Type</th>
<th class="last">Description</th>
</tr>
</thead>
<tbody>
<tr>
<td class="name"><code>server</code></td>
<td class="type">
<span class="param-type">Object</span>
</td>
<td class="description last">Reference to server enviroment object</td>
</tr>
</tbody>
</table>
<dl class="details">
<dt class="tag-source">Source:</dt>
<dd class="tag-source"><ul class="dummy"><li>
<a href="core_changenick.js.html">core/changenick.js</a>, <a href="core_changenick.js.html#line138">line 138</a>
</li></ul></dd>
</dl>
<h5>Returns:</h5>
<dl>
<dt>
Type
</dt>
<dd>
<span class="param-type">void</span>
</dd>
</dl>
<h4 class="name" id=".nickCheck"><span class="type-signature">(static) </span>nickCheck<span class="signature">(env)</span><span class="type-signature"></span></h4>
<div class="description">
Executes every time an incoming chat command is invoked
</div>
<h5>Parameters:</h5>
<table class="params">
<thead>
<tr>
<th>Name</th>
<th>Type</th>
<th class="last">Description</th>
</tr>
</thead>
<tbody>
<tr>
<td class="name"><code>env</code></td>
<td class="type">
<span class="param-type">Object</span>
</td>
<td class="description last">Enviroment object with references to core, server, socket & payload</td>
</tr>
</tbody>
</table>
<dl class="details">
<dt class="tag-source">Source:</dt>
<dd class="tag-source"><ul class="dummy"><li>
<a href="core_changenick.js.html">core/changenick.js</a>, <a href="core_changenick.js.html#line150">line 150</a>
</li></ul></dd>
</dl>
<h5>Returns:</h5>
<h4 class="name" id=".run"><span class="type-signature">(static) </span>run<span class="signature">(env)</span><span class="type-signature"> &rarr; {void}</span></h4>
<div class="description">
Executes when invoked by a remote client
</div>
<h5>Parameters:</h5>
<table class="params">
<thead>
<tr>
<th>Name</th>
<th>Type</th>
<th class="last">Description</th>
</tr>
</thead>
<tbody>
<tr>
<td class="name"><code>env</code></td>
<td class="type">
<span class="param-type">Object</span>
</td>
<td class="description last">Enviroment object with references to core, server, socket & payload</td>
</tr>
</tbody>
</table>
<dl class="details">
<dt class="tag-source">Source:</dt>
<dd class="tag-source"><ul class="dummy"><li>
<a href="core_changenick.js.html">core/changenick.js</a>, <a href="core_changenick.js.html#line22">line 22</a>
</li></ul></dd>
</dl>
<h5>Returns:</h5>
<dl>
<dt>
Type
</dt>
<dd>
<span class="param-type">void</span>
</dd>
</dl>
<h3 class="subsection-title">Type Definitions</h3>
<h4 class="name" id="~changenick/info">changenick/info</h4>
<div class="description">
Module meta information
</div>
<h5>Type:</h5>
<ul>
<li>
<span class="param-type">Object</span>
</li>
</ul>
<h5 class="subsection-title">Properties:</h5>
<table class="props">
<thead>
<tr>
<th>Name</th>
<th>Type</th>
<th class="last">Description</th>
</tr>
</thead>
<tbody>
<tr>
<td class="name"><code>name</code></td>
<td class="type">
<span class="param-type">string</span>
</td>
<td class="description last">Module command name</td>
</tr>
<tr>
<td class="name"><code>category</code></td>
<td class="type">
<span class="param-type">string</span>
</td>
<td class="description last">Module category name</td>
</tr>
<tr>
<td class="name"><code>description</code></td>
<td class="type">
<span class="param-type">string</span>
</td>
<td class="description last">Information about module</td>
</tr>
<tr>
<td class="name"><code>usage</code></td>
<td class="type">
<span class="param-type">string</span>
</td>
<td class="description last">Information about module usage</td>
</tr>
</tbody>
</table>
<dl class="details">
<dt class="tag-source">Source:</dt>
<dd class="tag-source"><ul class="dummy"><li>
<a href="core_changenick.js.html">core/changenick.js</a>, <a href="core_changenick.js.html#line197">line 197</a>
</li></ul></dd>
</dl>
<h4 class="name" id="~changenick/requiredData">changenick/requiredData</h4>
<div class="description">
The following payload properties are required to invoke this module:
"nick"
</div>
<h5>Type:</h5>
<ul>
<li>
<span class="param-type">Array</span>
</li>
</ul>
<dl class="details">
<dt class="tag-source">Source:</dt>
<dd class="tag-source"><ul class="dummy"><li>
<a href="core_changenick.js.html">core/changenick.js</a>, <a href="core_changenick.js.html#line189">line 189</a>
</li></ul></dd>
</dl>
</article>
</section>
</div>
<nav>
<h2><a href="index.html">Home</a></h2><h3>Modules</h3><ul><li><a href="module-addmod.html">addmod</a></li><li><a href="module-ban.html">ban</a></li><li><a href="module-changecolor.html">changecolor</a></li><li><a href="module-changenick.html">changenick</a></li><li><a href="module-chat.html">chat</a></li><li><a href="module-disconnect.html">disconnect</a></li><li><a href="module-dumb.html">dumb</a></li><li><a href="module-emote.html">emote</a></li><li><a href="module-forcecolor.html">forcecolor</a></li><li><a href="module-help.html">help</a></li><li><a href="module-invite.html">invite</a></li><li><a href="module-join.html">join</a></li><li><a href="module-kick.html">kick</a></li><li><a href="module-listusers.html">listusers</a></li><li><a href="module-morestats.html">morestats</a></li><li><a href="module-ping.html">ping</a></li><li><a href="module-reload.html">reload</a></li><li><a href="module-removemod.html">removemod</a></li><li><a href="module-saveconfig.html">saveconfig</a></li><li><a href="module-session.html">session</a></li><li><a href="module-shout.html">shout</a></li><li><a href="module-socketreply.html">socketreply</a></li><li><a href="module-speak.html">speak</a></li><li><a href="module-stats.html">stats</a></li><li><a href="module-unban.html">unban</a></li><li><a href="module-unbanall.html">unbanall</a></li><li><a href="module-whisper.html">whisper</a></li></ul>
</nav>
<br class="clear">
<footer>
Documentation generated by <a href="https://github.com/jsdoc/jsdoc">JSDoc 3.6.6</a> on Wed Jun 22 2022 10:04:25 GMT-0500 (Central Daylight Time)
</footer>
<script> prettyPrint(); </script>
<script src="scripts/linenumber.js"> </script>
</body>
</html>

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,604 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>JSDoc: Module: disconnect</title>
<script src="scripts/prettify/prettify.js"> </script>
<script src="scripts/prettify/lang-css.js"> </script>
<!--[if lt IE 9]>
<script src="//html5shiv.googlecode.com/svn/trunk/html5.js"></script>
<![endif]-->
<link type="text/css" rel="stylesheet" href="styles/prettify-tomorrow.css">
<link type="text/css" rel="stylesheet" href="styles/jsdoc-default.css">
</head>
<body>
<div id="main">
<h1 class="page-title">Module: disconnect</h1>
<section>
<header>
</header>
<article>
<div class="container-overview">
<div class="description">The server invokes this module each time a websocket connection is disconnected</div>
<dl class="details">
<dt class="tag-version">Version:</dt>
<dd class="tag-version"><ul class="dummy"><li>1.0.0</li></ul></dd>
<dt class="tag-author">Author:</dt>
<dd class="tag-author">
<ul>
<li>Marzavec ( https://github.com/marzavec )</li>
</ul>
</dd>
<dt class="tag-source">Source:</dt>
<dd class="tag-source"><ul class="dummy"><li>
<a href="internal_disconnect.js.html">internal/disconnect.js</a>, <a href="internal_disconnect.js.html#line1">line 1</a>
</li></ul></dd>
</dl>
</div>
<h3 class="subsection-title">Methods</h3>
<h4 class="name" id=".run"><span class="type-signature">(static) </span>run<span class="signature">(env)</span><span class="type-signature"> &rarr; {void}</span></h4>
<div class="description">
Executes when invoked by a remote client
</div>
<h5>Parameters:</h5>
<table class="params">
<thead>
<tr>
<th>Name</th>
<th>Type</th>
<th class="last">Description</th>
</tr>
</thead>
<tbody>
<tr>
<td class="name"><code>env</code></td>
<td class="type">
<span class="param-type">Object</span>
</td>
<td class="description last">Enviroment object with references to core, server, socket & payload</td>
</tr>
</tbody>
</table>
<dl class="details">
<dt class="tag-source">Source:</dt>
<dd class="tag-source"><ul class="dummy"><li>
<a href="internal_disconnect.js.html">internal/disconnect.js</a>, <a href="internal_disconnect.js.html#line19">line 19</a>
</li></ul></dd>
</dl>
<h5>Returns:</h5>
<dl>
<dt>
Type
</dt>
<dd>
<span class="param-type">void</span>
</dd>
</dl>
<h3 class="subsection-title">Type Definitions</h3>
<h4 class="name" id="~disconnect/info">disconnect/info</h4>
<div class="description">
Module meta information
</div>
<h5>Type:</h5>
<ul>
<li>
<span class="param-type">Object</span>
</li>
</ul>
<h5 class="subsection-title">Properties:</h5>
<table class="props">
<thead>
<tr>
<th>Name</th>
<th>Type</th>
<th class="last">Description</th>
</tr>
</thead>
<tbody>
<tr>
<td class="name"><code>name</code></td>
<td class="type">
<span class="param-type">string</span>
</td>
<td class="description last">Module command name</td>
</tr>
<tr>
<td class="name"><code>category</code></td>
<td class="type">
<span class="param-type">string</span>
</td>
<td class="description last">Module category name</td>
</tr>
<tr>
<td class="name"><code>description</code></td>
<td class="type">
<span class="param-type">string</span>
</td>
<td class="description last">Information about module</td>
</tr>
<tr>
<td class="name"><code>usage</code></td>
<td class="type">
<span class="param-type">string</span>
</td>
<td class="description last">Information about module usage</td>
</tr>
</tbody>
</table>
<dl class="details">
<dt class="tag-source">Source:</dt>
<dd class="tag-source"><ul class="dummy"><li>
<a href="internal_disconnect.js.html">internal/disconnect.js</a>, <a href="internal_disconnect.js.html#line52">line 52</a>
</li></ul></dd>
</dl>
<h4 class="name" id="~disconnect/requiredData">disconnect/requiredData</h4>
<div class="description">
The following payload properties are required to invoke this module:
"cmdKey"
</div>
<h5>Type:</h5>
<ul>
<li>
<span class="param-type">Array</span>
</li>
</ul>
<dl class="details">
<dt class="tag-source">Source:</dt>
<dd class="tag-source"><ul class="dummy"><li>
<a href="internal_disconnect.js.html">internal/disconnect.js</a>, <a href="internal_disconnect.js.html#line44">line 44</a>
</li></ul></dd>
</dl>
</article>
</section>
</div>
<nav>
<h2><a href="index.html">Home</a></h2><h3>Modules</h3><ul><li><a href="module-addmod.html">addmod</a></li><li><a href="module-ban.html">ban</a></li><li><a href="module-changecolor.html">changecolor</a></li><li><a href="module-changenick.html">changenick</a></li><li><a href="module-chat.html">chat</a></li><li><a href="module-disconnect.html">disconnect</a></li><li><a href="module-dumb.html">dumb</a></li><li><a href="module-emote.html">emote</a></li><li><a href="module-forcecolor.html">forcecolor</a></li><li><a href="module-help.html">help</a></li><li><a href="module-invite.html">invite</a></li><li><a href="module-join.html">join</a></li><li><a href="module-kick.html">kick</a></li><li><a href="module-listusers.html">listusers</a></li><li><a href="module-morestats.html">morestats</a></li><li><a href="module-ping.html">ping</a></li><li><a href="module-reload.html">reload</a></li><li><a href="module-removemod.html">removemod</a></li><li><a href="module-saveconfig.html">saveconfig</a></li><li><a href="module-session.html">session</a></li><li><a href="module-shout.html">shout</a></li><li><a href="module-socketreply.html">socketreply</a></li><li><a href="module-speak.html">speak</a></li><li><a href="module-stats.html">stats</a></li><li><a href="module-unban.html">unban</a></li><li><a href="module-unbanall.html">unbanall</a></li><li><a href="module-whisper.html">whisper</a></li></ul>
</nav>
<br class="clear">
<footer>
Documentation generated by <a href="https://github.com/jsdoc/jsdoc">JSDoc 3.6.6</a> on Wed Jun 22 2022 10:04:25 GMT-0500 (Central Daylight Time)
</footer>
<script> prettyPrint(); </script>
<script src="scripts/linenumber.js"> </script>
</body>
</html>

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,903 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>JSDoc: Module: emote</title>
<script src="scripts/prettify/prettify.js"> </script>
<script src="scripts/prettify/lang-css.js"> </script>
<!--[if lt IE 9]>
<script src="//html5shiv.googlecode.com/svn/trunk/html5.js"></script>
<![endif]-->
<link type="text/css" rel="stylesheet" href="styles/prettify-tomorrow.css">
<link type="text/css" rel="stylesheet" href="styles/jsdoc-default.css">
</head>
<body>
<div id="main">
<h1 class="page-title">Module: emote</h1>
<section>
<header>
</header>
<article>
<div class="container-overview">
<div class="description">Broadcasts an emote to the current channel</div>
<dl class="details">
<dt class="tag-version">Version:</dt>
<dd class="tag-version"><ul class="dummy"><li>1.0.0</li></ul></dd>
<dt class="tag-author">Author:</dt>
<dd class="tag-author">
<ul>
<li>Marzavec ( https://github.com/marzavec )</li>
</ul>
</dd>
<dt class="tag-source">Source:</dt>
<dd class="tag-source"><ul class="dummy"><li>
<a href="core_emote.js.html">core/emote.js</a>, <a href="core_emote.js.html#line1">line 1</a>
</li></ul></dd>
</dl>
</div>
<h3 class="subsection-title">Methods</h3>
<h4 class="name" id=".emoteCheck"><span class="type-signature">(static) </span>emoteCheck<span class="signature">(env)</span><span class="type-signature"></span></h4>
<div class="description">
Executes every time an incoming chat command is invoked;
hooks chat commands checking for /me
</div>
<h5>Parameters:</h5>
<table class="params">
<thead>
<tr>
<th>Name</th>
<th>Type</th>
<th class="last">Description</th>
</tr>
</thead>
<tbody>
<tr>
<td class="name"><code>env</code></td>
<td class="type">
<span class="param-type">Object</span>
</td>
<td class="description last">Enviroment object with references to core, server, socket & payload</td>
</tr>
</tbody>
</table>
<dl class="details">
<dt class="tag-source">Source:</dt>
<dd class="tag-source"><ul class="dummy"><li>
<a href="core_emote.js.html">core/emote.js</a>, <a href="core_emote.js.html#line98">line 98</a>
</li></ul></dd>
</dl>
<h5>Returns:</h5>
<h4 class="name" id=".initHooks"><span class="type-signature">(static) </span>initHooks<span class="signature">(server)</span><span class="type-signature"> &rarr; {void}</span></h4>
<div class="description">
Automatically executes once after server is ready to register this modules hooks
</div>
<h5>Parameters:</h5>
<table class="params">
<thead>
<tr>
<th>Name</th>
<th>Type</th>
<th class="last">Description</th>
</tr>
</thead>
<tbody>
<tr>
<td class="name"><code>server</code></td>
<td class="type">
<span class="param-type">Object</span>
</td>
<td class="description last">Reference to server enviroment object</td>
</tr>
</tbody>
</table>
<dl class="details">
<dt class="tag-source">Source:</dt>
<dd class="tag-source"><ul class="dummy"><li>
<a href="core_emote.js.html">core/emote.js</a>, <a href="core_emote.js.html#line85">line 85</a>
</li></ul></dd>
</dl>
<h5>Returns:</h5>
<dl>
<dt>
Type
</dt>
<dd>
<span class="param-type">void</span>
</dd>
</dl>
<h4 class="name" id=".run"><span class="type-signature">(static) </span>run<span class="signature">(env)</span><span class="type-signature"> &rarr; {void}</span></h4>
<div class="description">
Executes when invoked by a remote client
</div>
<h5>Parameters:</h5>
<table class="params">
<thead>
<tr>
<th>Name</th>
<th>Type</th>
<th class="last">Description</th>
</tr>
</thead>
<tbody>
<tr>
<td class="name"><code>env</code></td>
<td class="type">
<span class="param-type">Object</span>
</td>
<td class="description last">Enviroment object with references to core, server, socket & payload</td>
</tr>
</tbody>
</table>
<dl class="details">
<dt class="tag-source">Source:</dt>
<dd class="tag-source"><ul class="dummy"><li>
<a href="core_emote.js.html">core/emote.js</a>, <a href="core_emote.js.html#line38">line 38</a>
</li></ul></dd>
</dl>
<h5>Returns:</h5>
<dl>
<dt>
Type
</dt>
<dd>
<span class="param-type">void</span>
</dd>
</dl>
<h3 class="subsection-title">Type Definitions</h3>
<h4 class="name" id="~emote/info">emote/info</h4>
<div class="description">
Module meta information
</div>
<h5>Type:</h5>
<ul>
<li>
<span class="param-type">Object</span>
</li>
</ul>
<h5 class="subsection-title">Properties:</h5>
<table class="props">
<thead>
<tr>
<th>Name</th>
<th>Type</th>
<th class="last">Description</th>
</tr>
</thead>
<tbody>
<tr>
<td class="name"><code>name</code></td>
<td class="type">
<span class="param-type">string</span>
</td>
<td class="description last">Module command name</td>
</tr>
<tr>
<td class="name"><code>category</code></td>
<td class="type">
<span class="param-type">string</span>
</td>
<td class="description last">Module category name</td>
</tr>
<tr>
<td class="name"><code>description</code></td>
<td class="type">
<span class="param-type">string</span>
</td>
<td class="description last">Information about module</td>
</tr>
<tr>
<td class="name"><code>usage</code></td>
<td class="type">
<span class="param-type">string</span>
</td>
<td class="description last">Information about module usage</td>
</tr>
</tbody>
</table>
<dl class="details">
<dt class="tag-source">Source:</dt>
<dd class="tag-source"><ul class="dummy"><li>
<a href="core_emote.js.html">core/emote.js</a>, <a href="core_emote.js.html#line146">line 146</a>
</li></ul></dd>
</dl>
<h4 class="name" id="~emote/requiredData">emote/requiredData</h4>
<div class="description">
The following payload properties are required to invoke this module:
"text"
</div>
<h5>Type:</h5>
<ul>
<li>
<span class="param-type">Array</span>
</li>
</ul>
<dl class="details">
<dt class="tag-source">Source:</dt>
<dd class="tag-source"><ul class="dummy"><li>
<a href="core_emote.js.html">core/emote.js</a>, <a href="core_emote.js.html#line138">line 138</a>
</li></ul></dd>
</dl>
</article>
</section>
</div>
<nav>
<h2><a href="index.html">Home</a></h2><h3>Modules</h3><ul><li><a href="module-addmod.html">addmod</a></li><li><a href="module-ban.html">ban</a></li><li><a href="module-changecolor.html">changecolor</a></li><li><a href="module-changenick.html">changenick</a></li><li><a href="module-chat.html">chat</a></li><li><a href="module-disconnect.html">disconnect</a></li><li><a href="module-dumb.html">dumb</a></li><li><a href="module-emote.html">emote</a></li><li><a href="module-forcecolor.html">forcecolor</a></li><li><a href="module-help.html">help</a></li><li><a href="module-invite.html">invite</a></li><li><a href="module-join.html">join</a></li><li><a href="module-kick.html">kick</a></li><li><a href="module-listusers.html">listusers</a></li><li><a href="module-morestats.html">morestats</a></li><li><a href="module-ping.html">ping</a></li><li><a href="module-reload.html">reload</a></li><li><a href="module-removemod.html">removemod</a></li><li><a href="module-saveconfig.html">saveconfig</a></li><li><a href="module-session.html">session</a></li><li><a href="module-shout.html">shout</a></li><li><a href="module-socketreply.html">socketreply</a></li><li><a href="module-speak.html">speak</a></li><li><a href="module-stats.html">stats</a></li><li><a href="module-unban.html">unban</a></li><li><a href="module-unbanall.html">unbanall</a></li><li><a href="module-whisper.html">whisper</a></li></ul>
</nav>
<br class="clear">
<footer>
Documentation generated by <a href="https://github.com/jsdoc/jsdoc">JSDoc 3.6.6</a> on Wed Jun 22 2022 10:04:25 GMT-0500 (Central Daylight Time)
</footer>
<script> prettyPrint(); </script>
<script src="scripts/linenumber.js"> </script>
</body>
</html>

View File

@ -0,0 +1,903 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>JSDoc: Module: forcecolor</title>
<script src="scripts/prettify/prettify.js"> </script>
<script src="scripts/prettify/lang-css.js"> </script>
<!--[if lt IE 9]>
<script src="//html5shiv.googlecode.com/svn/trunk/html5.js"></script>
<![endif]-->
<link type="text/css" rel="stylesheet" href="styles/prettify-tomorrow.css">
<link type="text/css" rel="stylesheet" href="styles/jsdoc-default.css">
</head>
<body>
<div id="main">
<h1 class="page-title">Module: forcecolor</h1>
<section>
<header>
</header>
<article>
<div class="container-overview">
<div class="description">Forces a user nick to become a certain color</div>
<dl class="details">
<dt class="tag-version">Version:</dt>
<dd class="tag-version"><ul class="dummy"><li>1.0.0</li></ul></dd>
<dt class="tag-author">Author:</dt>
<dd class="tag-author">
<ul>
<li>Marzavec ( https://github.com/marzavec )</li>
</ul>
</dd>
<dt class="tag-source">Source:</dt>
<dd class="tag-source"><ul class="dummy"><li>
<a href="mod_forcecolor.js.html">mod/forcecolor.js</a>, <a href="mod_forcecolor.js.html#line1">line 1</a>
</li></ul></dd>
</dl>
</div>
<h3 class="subsection-title">Methods</h3>
<h4 class="name" id=".colorCheck"><span class="type-signature">(static) </span>colorCheck<span class="signature">(env)</span><span class="type-signature"></span></h4>
<div class="description">
Executes every time an incoming chat command is invoked;
hooks chat commands checking for /forcecolor
</div>
<h5>Parameters:</h5>
<table class="params">
<thead>
<tr>
<th>Name</th>
<th>Type</th>
<th class="last">Description</th>
</tr>
</thead>
<tbody>
<tr>
<td class="name"><code>env</code></td>
<td class="type">
<span class="param-type">Object</span>
</td>
<td class="description last">Enviroment object with references to core, server, socket & payload</td>
</tr>
</tbody>
</table>
<dl class="details">
<dt class="tag-source">Source:</dt>
<dd class="tag-source"><ul class="dummy"><li>
<a href="mod_forcecolor.js.html">mod/forcecolor.js</a>, <a href="mod_forcecolor.js.html#line125">line 125</a>
</li></ul></dd>
</dl>
<h5>Returns:</h5>
<h4 class="name" id=".initHooks"><span class="type-signature">(static) </span>initHooks<span class="signature">(server)</span><span class="type-signature"> &rarr; {void}</span></h4>
<div class="description">
Automatically executes once after server is ready to register this modules hooks
</div>
<h5>Parameters:</h5>
<table class="params">
<thead>
<tr>
<th>Name</th>
<th>Type</th>
<th class="last">Description</th>
</tr>
</thead>
<tbody>
<tr>
<td class="name"><code>server</code></td>
<td class="type">
<span class="param-type">Object</span>
</td>
<td class="description last">Reference to server enviroment object</td>
</tr>
</tbody>
</table>
<dl class="details">
<dt class="tag-source">Source:</dt>
<dd class="tag-source"><ul class="dummy"><li>
<a href="mod_forcecolor.js.html">mod/forcecolor.js</a>, <a href="mod_forcecolor.js.html#line112">line 112</a>
</li></ul></dd>
</dl>
<h5>Returns:</h5>
<dl>
<dt>
Type
</dt>
<dd>
<span class="param-type">void</span>
</dd>
</dl>
<h4 class="name" id=".run"><span class="type-signature">(static) </span>run<span class="signature">(env)</span><span class="type-signature"> &rarr; {void}</span></h4>
<div class="description">
Executes when invoked by a remote client
</div>
<h5>Parameters:</h5>
<table class="params">
<thead>
<tr>
<th>Name</th>
<th>Type</th>
<th class="last">Description</th>
</tr>
</thead>
<tbody>
<tr>
<td class="name"><code>env</code></td>
<td class="type">
<span class="param-type">Object</span>
</td>
<td class="description last">Enviroment object with references to core, server, socket & payload</td>
</tr>
</tbody>
</table>
<dl class="details">
<dt class="tag-source">Source:</dt>
<dd class="tag-source"><ul class="dummy"><li>
<a href="mod_forcecolor.js.html">mod/forcecolor.js</a>, <a href="mod_forcecolor.js.html#line35">line 35</a>
</li></ul></dd>
</dl>
<h5>Returns:</h5>
<dl>
<dt>
Type
</dt>
<dd>
<span class="param-type">void</span>
</dd>
</dl>
<h3 class="subsection-title">Type Definitions</h3>
<h4 class="name" id="~forcecolor/info">forcecolor/info</h4>
<div class="description">
Module meta information
</div>
<h5>Type:</h5>
<ul>
<li>
<span class="param-type">Object</span>
</li>
</ul>
<h5 class="subsection-title">Properties:</h5>
<table class="props">
<thead>
<tr>
<th>Name</th>
<th>Type</th>
<th class="last">Description</th>
</tr>
</thead>
<tbody>
<tr>
<td class="name"><code>name</code></td>
<td class="type">
<span class="param-type">string</span>
</td>
<td class="description last">Module command name</td>
</tr>
<tr>
<td class="name"><code>category</code></td>
<td class="type">
<span class="param-type">string</span>
</td>
<td class="description last">Module category name</td>
</tr>
<tr>
<td class="name"><code>description</code></td>
<td class="type">
<span class="param-type">string</span>
</td>
<td class="description last">Information about module</td>
</tr>
<tr>
<td class="name"><code>usage</code></td>
<td class="type">
<span class="param-type">string</span>
</td>
<td class="description last">Information about module usage</td>
</tr>
</tbody>
</table>
<dl class="details">
<dt class="tag-source">Source:</dt>
<dd class="tag-source"><ul class="dummy"><li>
<a href="mod_forcecolor.js.html">mod/forcecolor.js</a>, <a href="mod_forcecolor.js.html#line183">line 183</a>
</li></ul></dd>
</dl>
<h4 class="name" id="~forcecolor/requiredData">forcecolor/requiredData</h4>
<div class="description">
The following payload properties are required to invoke this module:
"nick", "color"
</div>
<h5>Type:</h5>
<ul>
<li>
<span class="param-type">Array</span>
</li>
</ul>
<dl class="details">
<dt class="tag-source">Source:</dt>
<dd class="tag-source"><ul class="dummy"><li>
<a href="mod_forcecolor.js.html">mod/forcecolor.js</a>, <a href="mod_forcecolor.js.html#line175">line 175</a>
</li></ul></dd>
</dl>
</article>
</section>
</div>
<nav>
<h2><a href="index.html">Home</a></h2><h3>Modules</h3><ul><li><a href="module-addmod.html">addmod</a></li><li><a href="module-ban.html">ban</a></li><li><a href="module-changecolor.html">changecolor</a></li><li><a href="module-changenick.html">changenick</a></li><li><a href="module-chat.html">chat</a></li><li><a href="module-disconnect.html">disconnect</a></li><li><a href="module-dumb.html">dumb</a></li><li><a href="module-emote.html">emote</a></li><li><a href="module-forcecolor.html">forcecolor</a></li><li><a href="module-help.html">help</a></li><li><a href="module-invite.html">invite</a></li><li><a href="module-join.html">join</a></li><li><a href="module-kick.html">kick</a></li><li><a href="module-listusers.html">listusers</a></li><li><a href="module-morestats.html">morestats</a></li><li><a href="module-ping.html">ping</a></li><li><a href="module-reload.html">reload</a></li><li><a href="module-removemod.html">removemod</a></li><li><a href="module-saveconfig.html">saveconfig</a></li><li><a href="module-session.html">session</a></li><li><a href="module-shout.html">shout</a></li><li><a href="module-socketreply.html">socketreply</a></li><li><a href="module-speak.html">speak</a></li><li><a href="module-stats.html">stats</a></li><li><a href="module-unban.html">unban</a></li><li><a href="module-unbanall.html">unbanall</a></li><li><a href="module-whisper.html">whisper</a></li></ul>
</nav>
<br class="clear">
<footer>
Documentation generated by <a href="https://github.com/jsdoc/jsdoc">JSDoc 3.6.6</a> on Wed Jun 22 2022 10:04:25 GMT-0500 (Central Daylight Time)
</footer>
<script> prettyPrint(); </script>
<script src="scripts/linenumber.js"> </script>
</body>
</html>

View File

@ -0,0 +1,830 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>JSDoc: Module: help</title>
<script src="scripts/prettify/prettify.js"> </script>
<script src="scripts/prettify/lang-css.js"> </script>
<!--[if lt IE 9]>
<script src="//html5shiv.googlecode.com/svn/trunk/html5.js"></script>
<![endif]-->
<link type="text/css" rel="stylesheet" href="styles/prettify-tomorrow.css">
<link type="text/css" rel="stylesheet" href="styles/jsdoc-default.css">
</head>
<body>
<div id="main">
<h1 class="page-title">Module: help</h1>
<section>
<header>
</header>
<article>
<div class="container-overview">
<div class="description">Outputs information about the servers current protocol</div>
<dl class="details">
<dt class="tag-version">Version:</dt>
<dd class="tag-version"><ul class="dummy"><li>1.0.0</li></ul></dd>
<dt class="tag-author">Author:</dt>
<dd class="tag-author">
<ul>
<li>Marzavec ( https://github.com/marzavec )</li>
</ul>
</dd>
<dt class="tag-source">Source:</dt>
<dd class="tag-source"><ul class="dummy"><li>
<a href="core_help.js.html">core/help.js</a>, <a href="core_help.js.html#line1">line 1</a>
</li></ul></dd>
</dl>
</div>
<h3 class="subsection-title">Methods</h3>
<h4 class="name" id=".helpCheck"><span class="type-signature">(static) </span>helpCheck<span class="signature">(env)</span><span class="type-signature"></span></h4>
<div class="description">
Executes every time an incoming chat command is invoked;
hooks chat commands checking for /help
</div>
<h5>Parameters:</h5>
<table class="params">
<thead>
<tr>
<th>Name</th>
<th>Type</th>
<th class="last">Description</th>
</tr>
</thead>
<tbody>
<tr>
<td class="name"><code>env</code></td>
<td class="type">
<span class="param-type">Object</span>
</td>
<td class="description last">Enviroment object with references to core, server, socket & payload</td>
</tr>
</tbody>
</table>
<dl class="details">
<dt class="tag-source">Source:</dt>
<dd class="tag-source"><ul class="dummy"><li>
<a href="core_help.js.html">core/help.js</a>, <a href="core_help.js.html#line92">line 92</a>
</li></ul></dd>
</dl>
<h5>Returns:</h5>
<h4 class="name" id=".initHooks"><span class="type-signature">(static) </span>initHooks<span class="signature">(server)</span><span class="type-signature"> &rarr; {void}</span></h4>
<div class="description">
Automatically executes once after server is ready to register this modules hooks
</div>
<h5>Parameters:</h5>
<table class="params">
<thead>
<tr>
<th>Name</th>
<th>Type</th>
<th class="last">Description</th>
</tr>
</thead>
<tbody>
<tr>
<td class="name"><code>server</code></td>
<td class="type">
<span class="param-type">Object</span>
</td>
<td class="description last">Reference to server enviroment object</td>
</tr>
</tbody>
</table>
<dl class="details">
<dt class="tag-source">Source:</dt>
<dd class="tag-source"><ul class="dummy"><li>
<a href="core_help.js.html">core/help.js</a>, <a href="core_help.js.html#line79">line 79</a>
</li></ul></dd>
</dl>
<h5>Returns:</h5>
<dl>
<dt>
Type
</dt>
<dd>
<span class="param-type">void</span>
</dd>
</dl>
<h4 class="name" id=".run"><span class="type-signature">(static) </span>run<span class="signature">(env)</span><span class="type-signature"> &rarr; {void}</span></h4>
<div class="description">
Executes when invoked by a remote client
</div>
<h5>Parameters:</h5>
<table class="params">
<thead>
<tr>
<th>Name</th>
<th>Type</th>
<th class="last">Description</th>
</tr>
</thead>
<tbody>
<tr>
<td class="name"><code>env</code></td>
<td class="type">
<span class="param-type">Object</span>
</td>
<td class="description last">Enviroment object with references to core, server, socket & payload</td>
</tr>
</tbody>
</table>
<dl class="details">
<dt class="tag-source">Source:</dt>
<dd class="tag-source"><ul class="dummy"><li>
<a href="core_help.js.html">core/help.js</a>, <a href="core_help.js.html#line15">line 15</a>
</li></ul></dd>
</dl>
<h5>Returns:</h5>
<dl>
<dt>
Type
</dt>
<dd>
<span class="param-type">void</span>
</dd>
</dl>
<h3 class="subsection-title">Type Definitions</h3>
<h4 class="name" id="~help/info">help/info</h4>
<div class="description">
Module meta information
</div>
<h5>Type:</h5>
<ul>
<li>
<span class="param-type">Object</span>
</li>
</ul>
<h5 class="subsection-title">Properties:</h5>
<table class="props">
<thead>
<tr>
<th>Name</th>
<th>Type</th>
<th class="last">Description</th>
</tr>
</thead>
<tbody>
<tr>
<td class="name"><code>name</code></td>
<td class="type">
<span class="param-type">string</span>
</td>
<td class="description last">Module command name</td>
</tr>
<tr>
<td class="name"><code>category</code></td>
<td class="type">
<span class="param-type">string</span>
</td>
<td class="description last">Module category name</td>
</tr>
<tr>
<td class="name"><code>description</code></td>
<td class="type">
<span class="param-type">string</span>
</td>
<td class="description last">Information about module</td>
</tr>
<tr>
<td class="name"><code>usage</code></td>
<td class="type">
<span class="param-type">string</span>
</td>
<td class="description last">Information about module usage</td>
</tr>
</tbody>
</table>
<dl class="details">
<dt class="tag-source">Source:</dt>
<dd class="tag-source"><ul class="dummy"><li>
<a href="core_help.js.html">core/help.js</a>, <a href="core_help.js.html#line118">line 118</a>
</li></ul></dd>
</dl>
</article>
</section>
</div>
<nav>
<h2><a href="index.html">Home</a></h2><h3>Modules</h3><ul><li><a href="module-addmod.html">addmod</a></li><li><a href="module-ban.html">ban</a></li><li><a href="module-changecolor.html">changecolor</a></li><li><a href="module-changenick.html">changenick</a></li><li><a href="module-chat.html">chat</a></li><li><a href="module-disconnect.html">disconnect</a></li><li><a href="module-dumb.html">dumb</a></li><li><a href="module-emote.html">emote</a></li><li><a href="module-forcecolor.html">forcecolor</a></li><li><a href="module-help.html">help</a></li><li><a href="module-invite.html">invite</a></li><li><a href="module-join.html">join</a></li><li><a href="module-kick.html">kick</a></li><li><a href="module-listusers.html">listusers</a></li><li><a href="module-morestats.html">morestats</a></li><li><a href="module-ping.html">ping</a></li><li><a href="module-reload.html">reload</a></li><li><a href="module-removemod.html">removemod</a></li><li><a href="module-saveconfig.html">saveconfig</a></li><li><a href="module-session.html">session</a></li><li><a href="module-shout.html">shout</a></li><li><a href="module-socketreply.html">socketreply</a></li><li><a href="module-speak.html">speak</a></li><li><a href="module-stats.html">stats</a></li><li><a href="module-unban.html">unban</a></li><li><a href="module-unbanall.html">unbanall</a></li><li><a href="module-whisper.html">whisper</a></li></ul>
</nav>
<br class="clear">
<footer>
Documentation generated by <a href="https://github.com/jsdoc/jsdoc">JSDoc 3.6.6</a> on Wed Jun 22 2022 10:04:25 GMT-0500 (Central Daylight Time)
</footer>
<script> prettyPrint(); </script>
<script src="scripts/linenumber.js"> </script>
</body>
</html>

Some files were not shown because too many files have changed in this diff Show More