mirror of
https://github.com/hack-chat/main.git
synced 2024-03-22 13:20:33 +08:00
commit
7ccbf56eeb
2
server/.gitignore → .gitignore
vendored
2
server/.gitignore → .gitignore
vendored
|
@ -60,4 +60,4 @@ typings/
|
|||
# next.js build output
|
||||
.next
|
||||
|
||||
config/
|
||||
server/config/
|
46
DOCUMENTATION.md
Normal file
46
DOCUMENTATION.md
Normal file
|
@ -0,0 +1,46 @@
|
|||
You can programmatically access hack.chat using the following commands via a websocket. To prevent getting disconnected, ping the server every 50 seconds. 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 `string`s). 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": "johndoe#fag"
|
||||
}
|
||||
```
|
||||
|
||||
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 `core`. `mod` is above `core`, so it can access `core` commands in addition to `mod` commands. `admin` is similarly above `mod`.
|
||||
|
||||
# `core`
|
||||
|
||||
|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.|
|
||||
|
||||
# `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.|
|
13
LICENSE
Normal file
13
LICENSE
Normal file
|
@ -0,0 +1,13 @@
|
|||
DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
|
||||
Version 2, December 2004
|
||||
|
||||
Copyright (C) 2004 Sam Hocevar <sam@hocevar.net>
|
||||
|
||||
Everyone is permitted to copy and distribute verbatim or modified
|
||||
copies of this license document, and changing it is allowed as long
|
||||
as the name is changed.
|
||||
|
||||
DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
|
||||
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
|
||||
|
||||
0. You just DO WHAT THE FUCK YOU WANT TO.
|
122
README.md
122
README.md
|
@ -1,107 +1,51 @@
|
|||
# Hack.Chat
|
||||
# hack.chat
|
||||
|
||||
[https://hack.chat/](https://hack.chat/) is a minimal, distraction-free, account-less, log-less, disappearing chat service that is easily deployable as your own service. The client comes bundled with LaTeX rendering provided by [https://github.com/Khan/KaTeX](https://github.com/Khan/KaTeX).
|
||||
[hack.chat](https://hack.chat/) is a minimal, distraction-free, accountless, logless, disappearing chat service which is easily deployable as your own service. The client comes bundled with LaTeX rendering provided by [KaTeX](https://github.com/Khan/KaTeX).
|
||||
|
||||
A list of software developed for the hack.chat framework can be found at: [https://github.com/hack-chat/3rd-party-software-list](https://github.com/hack-chat/3rd-party-software-list). This includes bots, clients, docker containers & more.
|
||||
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](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.
|
||||
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.md) and a [changelog](CHANGELOG.md).
|
||||
|
||||
## Getting Started
|
||||
# Installation
|
||||
|
||||
These instructions will get you a copy of the project up and running on your local machine for development and testing purposes. See deployment for notes on how to deploy the project on a live system.
|
||||
## Prerequisites
|
||||
|
||||
### Prerequisites
|
||||
- [node.js 8.10.0](https://nodejs.org/en/download/package-manager/#windows) or higher
|
||||
|
||||
The following versions are __required__:
|
||||
## Installing
|
||||
|
||||
```
|
||||
node >= 8.10.0
|
||||
npm >= 5.7.1
|
||||
```
|
||||
1. [Clone](https://help.github.com/articles/cloning-a-repository/) the repository: `git clone https://github.com/hack-chat/main.git`
|
||||
1. Change the directory: `cd main`
|
||||
1. Install the dependencies: `npm install`
|
||||
1. Configure: `npm start`
|
||||
|
||||
An installation guide for your operating system can be found at: [https://nodejs.org/en/download/package-manager/](https://nodejs.org/en/download/package-manager/)
|
||||
If you change the `websocketPort` option during the config setup then these changes will need to be reflected on [line 59 of client.js](https://github.com/hack-chat/main/blob/master/client/client.js#L59).
|
||||
|
||||
### Installing
|
||||
# Usage
|
||||
|
||||
First you will first need to clone this git, if you are unfamiliar with this process read [https://help.github.com/articles/cloning-a-repository/](https://help.github.com/articles/cloning-a-repository/), or to clone with git:
|
||||
1. `cd` into the repository: `cd main`
|
||||
1. Start the server: `npm start` with a process manager.
|
||||
1. Launch: `client/index.html`
|
||||
1. (OPTIONAL) If you want to deploy your hack.chat instance to a server, push everything except the `node_modules` directory and install the dependencies (`npm install`).
|
||||
|
||||
```
|
||||
git clone https://github.com/hack-chat/main.git
|
||||
```
|
||||
You can now run start the server software with a process manager like [PM2](https://github.com/Unitech/pm2) (e.g., `pm2 start server/main.js --name HackChat`). The client code will need to be copied into your http server directory. If you plan on using SSL to serve the client; you will need to use a reverse proxy, as TLS is not natively supported by the hack.chat server software (this may change in future releases).
|
||||
|
||||
Once cloned, the server will need to be setup. Using your terminal run:
|
||||
# Contributing
|
||||
|
||||
```
|
||||
cd main/server/
|
||||
npm install
|
||||
```
|
||||
- If you are modifying commands, make sure it is backwards compatible with the legacy client and you update the documentation accordingly.
|
||||
- Use [the template](templateCommand.js) to learn how to create new commands.
|
||||
- Use two space indents.
|
||||
- Name files in camelCase.
|
||||
- Scripts that do not default to strict mode (such as modules) must use the `'use strict'` directive.
|
||||
|
||||
Or on a Windows machine with Yarn installed:
|
||||
# Credits
|
||||
|
||||
```
|
||||
cd main/server/
|
||||
yarn install
|
||||
```
|
||||
* [**Marzavec**](https://github.com/marzavec) - *Initial work*
|
||||
* [**MinusGix**](https://github.com/MinusGix) - *Base updates*
|
||||
* Andrew Belt, https://github.com/AndrewBelt/hack.chat, for original base work
|
||||
* [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.
|
||||
|
||||
This will install the required packages to run hack.chat. Next the server will need to be configured, again in your terminal run:
|
||||
# License
|
||||
|
||||
```
|
||||
node main.js
|
||||
```
|
||||
|
||||
The configuration script will execute the initial server setup by requesting input. Follow the steps until it finishes:
|
||||
|
||||
```
|
||||
Note: npm/yarn run config will re-run this utility.
|
||||
|
||||
You will now be asked for the following:
|
||||
- Admin Name, the initial admin username
|
||||
- Admin Pass, the initial admin password
|
||||
- Port, the port for the websocket
|
||||
- Salt, the salt for username trip
|
||||
|
||||
prompt: adminName: admin
|
||||
prompt: adminPass: ****
|
||||
|
||||
prompt: websocketPort: (6060)
|
||||
prompt: tripSalt: ************
|
||||
|
||||
Config generated! You may now start the server normally.
|
||||
```
|
||||
|
||||
___Note:___ if you change the `websocketPort` option during the config setup then these changes will need to be reflected on line 64 of the [client.js](https://github.com/hack-chat/main/blob/master/client/client.js#L64).
|
||||
|
||||
After the config script runs, the process will exit & the server will need to be relaunched. For a production environment we recommend using [PM2](https://github.com/Unitech/pm2) to start the server:
|
||||
|
||||
```
|
||||
cd main/server/
|
||||
pm2 start main.js --name HackChat
|
||||
```
|
||||
|
||||
[Launch the client](./client/README.md) `main/client/index.html`, you may now begin development or deploy to production environment.
|
||||
|
||||
## Deployment
|
||||
|
||||
After the initial installation and configuration, push everything except the node_modules folder to the live server and re-run:
|
||||
|
||||
```
|
||||
npm install
|
||||
```
|
||||
|
||||
You can now run start the server software with a process manager like [PM2](https://github.com/Unitech/pm2). The client code will need to be copied into your http server directory. If you plan on using SSL to serve the client; you will need to use a reverse proxy, as TLS is not natively supported by the hack.chat server software (this may change in future releases).
|
||||
|
||||
## Authors
|
||||
|
||||
* **Marzavec** - *Initial work* - [https://github.com/marzavec](https://github.com/marzavec)
|
||||
* **MinusGix** - *Base updates* - [https://github.com/MinusGix](https://github.com/MinusGix)
|
||||
|
||||
See also the list of [contributors](https://github.com/hack-chat/main/graphs/contributors) who participated in this project.
|
||||
|
||||
## License
|
||||
|
||||
This project is licensed under the WTFPL License - see the [http://www.wtfpl.net/txt/copying/](http://www.wtfpl.net/txt/copying/) file for details
|
||||
|
||||
## Acknowledgments
|
||||
|
||||
* Andrew Belt, [https://github.com/AndrewBelt/hack.chat](https://github.com/AndrewBelt/hack.chat), for original base work
|
||||
* wwandrew [https://github.com/wwandrew/](https://github.com/wwandrew/), for finding server flaws (including attack vectors) and submitting ~~___incredibly detailed___~~ bug reports
|
||||
This project is licensed under the [WTFPL License](LICENSE).
|
||||
|
|
|
@ -36,13 +36,13 @@ function $(query) {
|
|||
function localStorageGet(key) {
|
||||
try {
|
||||
return window.localStorage[key]
|
||||
} catch(e) { }
|
||||
} catch (e) { }
|
||||
}
|
||||
|
||||
function localStorageSet(key, val) {
|
||||
try {
|
||||
window.localStorage[key] = val
|
||||
} catch(e) { }
|
||||
} catch (e) { }
|
||||
}
|
||||
|
||||
var ws;
|
||||
|
@ -214,10 +214,12 @@ function pushMessage(args) {
|
|||
// Temporary hotfix for \rule spamming, see https://github.com/Khan/KaTeX/issues/109
|
||||
textEl.innerHTML = textEl.innerHTML.replace(/\\rule|\\\\\s*\[.*?\]/g, '');
|
||||
try {
|
||||
renderMathInElement(textEl, {delimiters: [
|
||||
renderMathInElement(textEl, {
|
||||
delimiters: [
|
||||
{ left: "$$", right: "$$", display: true },
|
||||
{ left: "$", right: "$", display: false },
|
||||
]})
|
||||
]
|
||||
})
|
||||
} catch (e) {
|
||||
console.warn(e);
|
||||
}
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
"name": "hack.chat-v2",
|
||||
"version": "2.0.1",
|
||||
"description": "a minimal distraction free chat application",
|
||||
"main": "main.js",
|
||||
"main": "server/main.js",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "git+https://github.com/hack-chat/main.git"
|
||||
|
@ -12,11 +12,10 @@
|
|||
"npm": ">= 5.7.1"
|
||||
},
|
||||
"scripts": {
|
||||
"test": "echo \"Error: no test specified\" && exit 1",
|
||||
"start": "node server.js",
|
||||
"config": "node src/scripts/configure.js",
|
||||
"debug": "node src/scripts/debug.js",
|
||||
"dev": "node src/scripts/debug.js"
|
||||
"start": "node server/main.js",
|
||||
"config": "node server/src/scripts/configure.js",
|
||||
"debug": "node server/src/scripts/debug.js",
|
||||
"dev": "node server/src/scripts/debug.js"
|
||||
},
|
||||
"author": "Marzavec",
|
||||
"license": "WTFPL",
|
|
@ -1 +0,0 @@
|
|||
(TODO)
|
|
@ -2,8 +2,6 @@
|
|||
Description: Adds the target trip to the mod list then elevates the uType
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
|
||||
exports.run = async (core, server, socket, data) => {
|
||||
if (socket.uType != 'admin') {
|
||||
// ignore if not admin
|
||||
|
|
|
@ -2,8 +2,6 @@
|
|||
Description: Outputs all current channels and their user nicks
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
|
||||
exports.run = async (core, server, socket, data) => {
|
||||
if (socket.uType != 'admin') {
|
||||
// ignore if not admin
|
||||
|
|
|
@ -2,8 +2,6 @@
|
|||
Description: Clears and resets the command modules, outputting any errors
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
|
||||
exports.run = async (core, server, socket, data) => {
|
||||
if (socket.uType != 'admin') {
|
||||
// ignore if not admin
|
||||
|
@ -34,3 +32,4 @@ exports.info = {
|
|||
name: 'reload',
|
||||
description: '(Re)loads any new commands into memory, outputs errors if any'
|
||||
};
|
||||
|
||||
|
|
|
@ -2,8 +2,6 @@
|
|||
Description: Writes any changes to the config to the disk
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
|
||||
exports.run = async (core, server, socket, data) => {
|
||||
if (socket.uType != 'admin') {
|
||||
// ignore if not admin
|
||||
|
|
|
@ -2,8 +2,6 @@
|
|||
Description: Emmits a server-wide message as `info`
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
|
||||
exports.run = async (core, server, socket, data) => {
|
||||
if (socket.uType != 'admin') {
|
||||
// ignore if not admin
|
||||
|
|
|
@ -2,8 +2,6 @@
|
|||
Description: Generates a semi-unique channel name then broadcasts it to each client
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
|
||||
const verifyNickname = (nick) => {
|
||||
return /^[a-zA-Z0-9_]{1,24}$/.test(nick);
|
||||
};
|
||||
|
|
|
@ -2,8 +2,6 @@
|
|||
Description: Rebroadcasts any `text` to all clients in a `channel`
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
|
||||
const parseText = (text) => {
|
||||
if (typeof text !== 'string') {
|
||||
return false;
|
||||
|
|
|
@ -4,8 +4,6 @@
|
|||
by a client to have the connection severed.
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
|
||||
exports.run = async (core, server, socket, data) => {
|
||||
if (socket.channel) {
|
||||
server.broadcast({
|
||||
|
|
|
@ -2,8 +2,6 @@
|
|||
Description: Outputs the current command module list or command categories
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
|
||||
const stripIndents = require('common-tags').stripIndents;
|
||||
|
||||
exports.run = async (core, server, socket, data) => {
|
||||
|
|
|
@ -2,8 +2,6 @@
|
|||
Description: Generates a semi-unique channel name then broadcasts it to each client
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
|
||||
const verifyNickname = (nick) => {
|
||||
return /^[a-zA-Z0-9_]{1,24}$/.test(nick);
|
||||
};
|
||||
|
|
|
@ -2,8 +2,6 @@
|
|||
Description: Initial entry point, applies `channel` and `nick` to the calling socket
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
|
||||
const crypto = require('crypto');
|
||||
|
||||
const hash = (password) => {
|
||||
|
|
|
@ -2,8 +2,6 @@
|
|||
Description: Outputs more info than the legacy stats command
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
|
||||
const stripIndents = require('common-tags').stripIndents;
|
||||
|
||||
const formatTime = (time) => {
|
||||
|
|
|
@ -2,8 +2,6 @@
|
|||
Description: Generates a semi-unique channel name then broadcasts it to each client
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
|
||||
exports.run = async (core, server, socket, data) => {
|
||||
if (server._police.frisk(socket.remoteAddress, 6)) {
|
||||
server.reply({
|
||||
|
|
|
@ -2,8 +2,6 @@
|
|||
Description: Legacy stats output, kept for compatibility, outputs user and channel count
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
|
||||
exports.run = async (core, server, socket, data) => {
|
||||
let ips = {};
|
||||
let channels = {};
|
||||
|
|
|
@ -2,8 +2,6 @@
|
|||
Description: Adds the target socket's ip to the ratelimiter
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
|
||||
exports.run = async (core, server, socket, data) => {
|
||||
if (socket.uType == 'user') {
|
||||
// ignore if not mod or admin
|
||||
|
|
|
@ -2,8 +2,6 @@
|
|||
Description: Forces a change on the target socket's channel, then broadcasts event
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
|
||||
exports.run = async (core, server, socket, data) => {
|
||||
if (socket.uType === 'user') {
|
||||
// ignore if not mod or admin
|
||||
|
|
|
@ -2,8 +2,6 @@
|
|||
Description: Removes a target ip from the ratelimiter
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
|
||||
exports.run = async (core, server, socket, data) => {
|
||||
if (socket.uType == 'user') {
|
||||
// ignore if not mod or admin
|
||||
|
|
|
@ -8,15 +8,13 @@
|
|||
*
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
|
||||
class Police {
|
||||
/**
|
||||
* Create a ratelimiter instance.
|
||||
*/
|
||||
constructor () {
|
||||
this._records = {};
|
||||
this._halflife = 30000; // ms
|
||||
this._halflife = 30 * 1000; // milliseconds
|
||||
this._threshold = 25;
|
||||
this._hashes = [];
|
||||
}
|
||||
|
|
|
@ -7,8 +7,6 @@
|
|||
*
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
|
||||
const wsServer = require('ws').Server;
|
||||
const socketReady = require('ws').OPEN;
|
||||
const crypto = require('crypto');
|
||||
|
|
|
@ -7,8 +7,6 @@
|
|||
*
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
|
||||
const path = require('path');
|
||||
const chalk = require('chalk');
|
||||
const didYouMean = require('didyoumean2');
|
||||
|
|
|
@ -8,8 +8,6 @@
|
|||
*
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
|
||||
const stripIndents = require('common-tags').stripIndents;
|
||||
const dateFormat = require('dateformat');
|
||||
const chalk = require('chalk');
|
||||
|
|
|
@ -7,8 +7,6 @@
|
|||
*
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
|
||||
const read = require('readdir-recursive');
|
||||
const path = require('path');
|
||||
|
||||
|
|
|
@ -7,8 +7,6 @@
|
|||
*
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
|
||||
class Stats {
|
||||
/**
|
||||
* Create a stats instance.
|
||||
|
|
|
@ -2,8 +2,6 @@
|
|||
Description: This is a template module that should not be on prod
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
|
||||
// you can require() modules here
|
||||
|
||||
// this function will only be only in the scope of the module
|
Loading…
Reference in New Issue
Block a user