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

189 lines
5.3 KiB
JavaScript
Raw Normal View History

2018-03-10 15:47:00 +08:00
/*
Description: Initial entry point, applies `channel` and `nick` to the calling socket
2018-03-10 15:47:00 +08:00
*/
import * as UAC from '../utility/UAC/_info';
// module support functions
2018-03-10 15:47:00 +08:00
const crypto = require('crypto');
const hash = (password) => {
2019-11-07 15:35:23 +08:00
const sha = crypto.createHash('sha256');
2018-03-10 15:47:00 +08:00
sha.update(password);
return sha.digest('base64').substr(0, 6);
};
2018-03-10 15:47:00 +08:00
// exposed "login" function to allow hooks to verify user join events
// returns object containing user info or string if error
2019-11-07 15:35:23 +08:00
export function parseNickname(core, data) {
const userInfo = {
2020-09-08 12:51:47 +08:00
nick: data.nick,
2020-03-13 02:28:20 +08:00
uType: 'user', /* @legacy */
trip: null,
level: UAC.levels.default,
};
if (!UAC.verifyNickname(userInfo.nick)) {
// return error as string
2020-09-08 12:51:47 +08:00
// @todo Remove english and change to numeric id
return 'Nickname must consist of up to 24 letters, numbers, and underscores';
}
2020-09-08 12:51:47 +08:00
let password = data.pass || false;
if (hash(password + core.config.tripSalt) === core.config.adminTrip) {
2020-03-13 02:28:20 +08:00
userInfo.uType = 'admin'; /* @legacy */
userInfo.trip = 'Admin';
userInfo.level = UAC.levels.admin;
2019-11-07 15:35:23 +08:00
} else if (userInfo.nick.toLowerCase() === core.config.adminName.toLowerCase()) {
// they've got the main-admin name while not being an admin
2020-09-08 12:51:47 +08:00
// @todo Remove english and change to numeric id
return 'You are not the admin, liar!';
} else if (password) {
userInfo.trip = hash(password + core.config.tripSalt);
}
// TODO: disallow moderator impersonation
2019-11-07 15:35:23 +08:00
// for (const mod of core.config.mods) {
core.config.mods.forEach((mod) => {
if (userInfo.trip === mod.trip) {
2020-03-13 02:28:20 +08:00
userInfo.uType = 'mod'; /* @legacy */
userInfo.level = UAC.levels.moderator;
}
2019-11-07 15:35:23 +08:00
});
return userInfo;
2019-11-07 15:35:23 +08:00
}
// module main
2019-11-07 15:35:23 +08:00
export async function run(core, server, socket, data) {
2018-06-04 15:07:24 +08:00
// check for spam
2019-11-07 15:35:23 +08:00
if (server.police.frisk(socket.address, 3)) {
return server.reply({
2020-09-08 12:51:47 +08:00
cmd: 'warn', // @todo Remove english and change to numeric id
2019-11-07 15:35:23 +08:00
text: 'You are joining channels too fast. Wait a moment and try again.',
2018-03-10 15:47:00 +08:00
}, socket);
}
2018-06-04 15:07:24 +08:00
// calling socket already in a channel
2020-09-08 12:51:47 +08:00
// @todo Multichannel update
2018-03-10 15:47:00 +08:00
if (typeof socket.channel !== 'undefined') {
2020-09-08 12:51:47 +08:00
return server.reply({
cmd: 'warn', // @todo Remove this
text: 'Joining more than one channel is not currently supported',
}, socket);
2018-03-10 15:47:00 +08:00
}
2018-06-04 15:07:24 +08:00
// check user input
if (typeof data.channel !== 'string' || typeof data.nick !== 'string') {
2019-11-07 15:35:23 +08:00
return true;
}
2019-11-07 15:35:23 +08:00
const channel = data.channel.trim();
2018-03-10 15:47:00 +08:00
if (!channel) {
2018-06-04 15:07:24 +08:00
// must join a non-blank channel
2019-11-07 15:35:23 +08:00
return true;
2018-03-10 15:47:00 +08:00
}
2019-11-07 15:35:23 +08:00
const userInfo = this.parseNickname(core, data);
if (typeof userInfo === 'string') {
return server.reply({
2020-09-08 12:51:47 +08:00
cmd: 'warn', // @todo Remove english and change to numeric id
2019-11-07 15:35:23 +08:00
text: userInfo,
2018-03-10 15:47:00 +08:00
}, socket);
}
2018-06-04 15:07:24 +08:00
// check if the nickname already exists in the channel
2019-11-07 15:35:23 +08:00
const userExists = server.findSockets({
2018-04-29 13:29:38 +08:00
channel: data.channel,
2019-11-07 15:35:23 +08:00
nick: (targetNick) => targetNick.toLowerCase() === userInfo.nick.toLowerCase(),
2018-04-29 13:29:38 +08:00
});
2018-03-10 15:47:00 +08:00
2018-04-29 13:29:38 +08:00
if (userExists.length > 0) {
2018-06-04 15:07:24 +08:00
// that nickname is already in that channel
return server.reply({
2020-09-08 12:51:47 +08:00
cmd: 'warn', // @todo Remove english and change to numeric id
2019-11-07 15:35:23 +08:00
text: 'Nickname taken',
2018-04-29 13:29:38 +08:00
}, socket);
2018-03-10 15:47:00 +08:00
}
2020-09-08 12:51:47 +08:00
// populate final userinfo fields
// @TODO: this could be move into parseNickname, changing the function name to match
2020-03-13 02:28:20 +08:00
userInfo.hash = server.getSocketHash(socket);
2020-09-08 12:51:47 +08:00
userInfo.userid = socket.userid;
2018-03-10 15:47:00 +08:00
2020-09-08 12:51:47 +08:00
// @TODO: place this within it's own function allowing import
2018-06-04 15:07:24 +08:00
// prepare to notify channel peers
2019-11-07 15:35:23 +08:00
const newPeerList = server.findSockets({ channel: data.channel });
2020-03-13 02:28:20 +08:00
const nicks = []; /* @legacy */
const users = [];
2018-06-04 15:07:24 +08:00
2019-11-07 15:35:23 +08:00
const joinAnnouncement = {
2018-03-10 15:47:00 +08:00
cmd: 'onlineAdd',
nick: userInfo.nick,
trip: userInfo.trip || 'null',
2020-03-13 02:28:20 +08:00
utype: userInfo.uType, /* @legacy */
hash: userInfo.hash,
level: userInfo.level,
2020-03-13 02:28:20 +08:00
userid: userInfo.userid,
channel: data.channel,
2018-04-29 13:29:38 +08:00
};
2018-06-04 15:07:24 +08:00
// send join announcement and prep online set
2019-11-07 15:35:23 +08:00
for (let i = 0, l = newPeerList.length; i < l; i += 1) {
2018-04-29 13:29:38 +08:00
server.reply(joinAnnouncement, newPeerList[i]);
2020-03-13 02:28:20 +08:00
nicks.push(newPeerList[i].nick); /* @legacy */
users.push({
nick: newPeerList[i].nick,
trip: newPeerList[i].trip,
utype: newPeerList[i].uType, /* @legacy */
2020-03-14 02:40:12 +08:00
hash: newPeerList[i].hash,
2020-03-13 02:28:20 +08:00
level: newPeerList[i].level,
userid: newPeerList[i].userid,
channel: data.channel,
isme: false,
});
2018-04-29 13:29:38 +08:00
}
2018-03-10 15:47:00 +08:00
2018-06-04 15:07:24 +08:00
// store user info
2020-03-13 02:28:20 +08:00
socket.uType = userInfo.uType; /* @legacy */
socket.nick = userInfo.nick;
2020-03-13 02:28:20 +08:00
socket.trip = userInfo.trip;
socket.channel = data.channel; /* @legacy */
socket.hash = userInfo.hash;
socket.level = userInfo.level;
2020-03-13 02:28:20 +08:00
nicks.push(socket.nick); /* @legacy */
users.push({
nick: socket.nick,
trip: socket.trip,
utype: socket.uType,
2020-03-14 02:40:12 +08:00
hash: socket.hash,
2020-03-13 02:28:20 +08:00
level: socket.level,
userid: socket.userid,
channel: data.channel,
isme: true,
});
2018-03-10 15:47:00 +08:00
2018-06-04 15:07:24 +08:00
// reply with channel peer list
2018-03-10 15:47:00 +08:00
server.reply({
cmd: 'onlineSet',
2020-03-13 02:28:20 +08:00
nicks, /* @legacy */
users,
2018-03-10 15:47:00 +08:00
}, socket);
2018-06-04 15:07:24 +08:00
// stats are fun
2019-03-19 14:36:21 +08:00
core.stats.increment('users-joined');
2018-03-10 15:47:00 +08:00
2019-11-07 15:35:23 +08:00
return true;
}
export const requiredData = ['channel', 'nick'];
export const info = {
2018-05-13 18:33:22 +08:00
name: 'join',
description: 'Place calling socket into target channel with target nick & broadcast event to channel',
usage: `
2020-09-08 12:51:47 +08:00
API: { cmd: 'join', nick: '<your nickname>', pass: '<optional password>', channel: '<target channel>' }`,
};