Merge branch 'master' of gitlab.com:Hri7566/mpp-server

This commit is contained in:
Hri7566 2022-07-14 02:39:13 -04:00
commit 32c6b0ffa8
15 changed files with 819 additions and 3438 deletions

View File

@ -2,22 +2,27 @@ module.exports = Object.seal({
port: 8443,
motd: "big th0nk",
_id_PrivateKey: process.env.SALT,
defaultUsername: "Anonymous",
// defaultRoomColor: "#3b5054",
defaultRoomColor: "#480505",
// defaultLobbyColor: "#19b4b9",
// defaultLobbyColor: "#76b0db",
// defaultLobbyColor2: "#801014",
// defaultLobbyColor2: "#276491",
defaultLobbyColor: "#9900ff",
defaultLobbyColor2: "#5900af",
defaultLobbyColor: "#76b0db",
defaultLobbyColor2: "#276491",
// defaultLobbyColor: "#9900ff",
// defaultLobbyColor2: "#5900af",
defaultUsername: "Anonymous",
adminpass: process.env.ADMINPASS,
ssl: process.env.SSL,
serveFiles: true,
defaultRoomSettings: {
color: "#3b5054",
color2: "#001014",
// color: "#3b5054",
// color2: "#001014",
color: "#480505",
crownsolo: false,
visible: true
}
},
hostDevFiles: false,
enableMPPCloneBot: true
});

View File

@ -34,3 +34,38 @@ let console = process.platform == 'win32' ? new AsyncConsole("", input => {
}
}) : {};
*/
// dev environment
if (config.hostDevFiles) {
let express_logger = new (require("./src/Logger"))("Express Server");
const express = require('express');
const app = express();
const path = require('path');
var http = require('http');
let dir = path.join(__dirname, 'mpp.hri7566.info');
app.use(express.static(path.join(__dirname, dir)));
app.get('*', (req, res, next) => {
let file = path.join(dir, req.path);
if (fs.existsSync(file)) {
res.sendFile(file);
} else {
res.sendFile(path.join(dir, 'index.html'));
}
});
const express_port = 8075;
http.createServer(app).listen(express_port);
}
if (config.enableMPPCloneBot) {
require('./mppclonebot');
}

231
mppclonebot.js Normal file
View File

@ -0,0 +1,231 @@
const Client = require('mppclone-client');
const Logger = require('./src/Logger');
const { EventEmitter } = require('events');
const token = process.env.MPPCLONE_TOKEN;
class Command {
static commands = {};
static getUsage(us, prefix) {
return us.split('%PREFIX%').join(prefix);
}
constructor(cmd, desc, usage, minargs, func, minrank, hidden) {
this.cmd = typeof cmd == 'object' ? cmd : [cmd];
this.desc = desc || "No description";
this.usage = usage || "No usage";
this.minargs = minargs || 0;
this.func = func;
this.minrank = minrank || 0;
this.hidden = hidden || false;
Command.commands[this.cmd[0]] = this;
}
}
class Rank {
static ranks = {};
static user_ranks = {};
static setRank(_id, rank) {
Rank.user_ranks[_id] = rank;
}
static getRank(_id) {
return Rank.user_ranks[_id];
}
constructor(name, desc, minrank) {
this.name = name;
this.desc = desc;
this.minrank = minrank;
Rank.ranks[name] = this;
}
}
new Rank("User", "Default rank", 0);
new Rank("Mod", "Moderator rank", 1);
new Rank("Admin", "Administrator rank", 2);
new Rank("Owner", "Owner rank", 3);
class Prefix {
static prefixes = {};
static hasAnyPrefix(str) {
for (let i in Prefix.prefixes) {
if (str.startsWith(Prefix.prefixes[i].prefix)) {
return true;
}
}
}
static getPrefixFromString(str) {
for (let i in Prefix.prefixes) {
if (str.startsWith(Prefix.prefixes[i].prefix)) {
return Prefix.prefixes[i];
}
}
}
constructor(id, prefix) {
this.id = id;
this.prefix = prefix;
Prefix.prefixes[id] = this;
}
}
class Bot extends EventEmitter {
constructor(cl) {
super();
this.logger = new Logger('MPPClone Bot');
this.client = cl;
this.bindEventListeners();
this.userset = {
name: 'mpp.hri7566.info [indev]', // TODO change this name
color: '#76b0db'
};
this.chatBuffer = [];
this.chatBufferCycleCounter = 0;
this.chatBufferCycle();
this.client.start();
this.client.setChannel('✧𝓓𝓔𝓥 𝓡𝓸𝓸𝓶✧');
}
bindEventListeners() {
this.client.on('a', msg => {
this.emit('receiveChat', msg);
});
this.client.on('ch', msg => {
this.emit('resetName', msg);
})
this.client.on('hi', msg => {
this.emit('online', msg);
});
this.client.on('t', msg => {
this.emit('resetName', msg);
});
this.on('resetName', () => {
if (this.client.getOwnParticipant().name !== this.userset.name || this.client.getOwnParticipant().color !== this.userset.color) {
this.client.sendArray([{
m: 'userset',
set: this.userset
}]);
}
});
this.on('receiveChat', msg => {
if (Prefix.hasAnyPrefix(msg.a)) {
msg.prefix = Prefix.getPrefixFromString(msg.a);
this.emit('runCommand', msg);
}
});
this.on('addToChatBuffer', msg => {
this.chatBuffer.push(msg);
});
this.on('runCommand', msg => {
if (!msg.prefix) return;
msg.args = msg.a.split(' ');
msg.cmd = msg.args[0].substring(msg.prefix.prefix.length).trim();
msg.argcat = msg.a.substring(msg.args[0].length).trim();
let rank = Rank.getRank(msg.p._id);
if (!rank) {
rank = Rank.ranks['User'];
Rank.setRank(msg.p._id, rank);
}
msg.rank = rank;
for (let cmd of Object.values(Command.commands)) {
if (!cmd.cmd.includes(msg.cmd)) continue;
console.log(msg.cmd, cmd.cmd);
if (msg.args.length < cmd.minargs) return;
if (msg.rank.id < cmd.minrank) return;
try {
let out = cmd.func(msg);
if (!out) return;
out = out.split('\n').join(' ').split('\t').join(' ').split('\r').join(' ');
if (out !== '') {
this.emit('addToChatBuffer', {
m: 'a',
message: out,
p: msg.p._id
});
}
} catch (e) {
this.emit('addToChatBuffer', {
m: 'a',
message: 'An error has occurred.',
p: msg.p._id
});
}
}
});
this.on('online', () => {
this.logger.log('Connected');
});
}
async chatBufferCycle() {
if (this.chatBuffer.length <= 0) {
setTimeout(() => {
this.chatBufferCycle();
});
return;
}
this.chatBufferCycleCounter++;
let time = 0;
if (this.chatBufferCycleCounter > 4) {
time += 1000;
}
setTimeout(() => {
let nextMessage = this.chatBuffer.shift();
this.client.sendArray([nextMessage]);
this.chatBufferCycle();
this.chatBufferCycleCounter--;
}, time);
}
}
new Prefix('hmpp!', 'hmpp!');
new Prefix('h!', 'h!');
new Command(['help', 'cmds', 'h'], 'List all commands', '%PREFIX%help', 0, (msg) => {
let cmds = 'Commands: ';
for (let cmd of Object.values(Command.commands)) {
if (cmd.hidden) continue;
cmds += `${cmd.cmd[0]}, `;
}
cmds = cmds.substring(0, cmds.length - 2).trim();
return cmds;
}, 0, false);
new Command(['users'], 'See how many users are online', `%PREFIX%users`, 0, (msg) => {
console.log(SERVER.connections.size);
return `There are ${SERVER.connections.size} users on HMPP.`;
}, 0, false);
let cl = new Client("wss://mppclone.com:8443", token);
let bot = new Bot(cl);

3275
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -31,7 +31,7 @@
"keccak": "^2.1.0",
"level": "^7.0.0",
"mongoose": "^5.12.7",
"node-json-color-stringify": "^1.1.0",
"mppclone-client": "^1.0.0",
"nodemon": "^2.0.15",
"ws": "^7.2.3"
}

View File

@ -7,6 +7,7 @@ const RoomSettings = require('./RoomSettings.js');
const ftc = require('fancy-text-converter');
const Notification = require('./Notification');
const Color = require('./Color');
const { getTimeColor } = require('./ColorEncoder.js');
class Channel extends EventEmitter {
constructor(server, _id, settings) {
@ -16,7 +17,16 @@ class Channel extends EventEmitter {
this.server = server;
this.crown;
this.crowndropped = false;
this.settings = settings;
if (this.isLobby(this._id)) {
this.settings = new RoomSettings(this.server.lobbySettings);
// this.settings.lobby = true;
// this.settings.color = this.server.lobbySettings.color;
// this.settings.color2 = this.server.lobbySettings.color2;
} else {
this.settings = new RoomSettings(settings, 'user');
}
this.chatmsgs = [];
this.ppl = new Map();
this.connections = [];
@ -32,8 +42,8 @@ class Channel extends EventEmitter {
if (err) {
return;
}
this.settings = set.settings;
this.settings = RoomSettings.changeSettings(this.settings, true);
this.chatmsgs = set.chat;
this.connections.forEach(cl => {
cl.sendArray([{
@ -43,6 +53,13 @@ class Channel extends EventEmitter {
});
this.setData();
});
if (this.isLobby(this._id)) {
this.colorInterval = setInterval(() => {
this.setDefaultLobbyColorBasedOnDate();
}, 1000 * 60 * 5);
this.setDefaultLobbyColorBasedOnDate();
}
}
setChatArray(arr) {
@ -54,40 +71,67 @@ class Channel extends EventEmitter {
this.setData();
}
setDefaultLobbyColorBasedOnDate() {
let col = getTimeColor();
let col2 = new Color(col.r - 0x40, col.g - 0x40, col.b - 0x40);
this.settings.changeSettings({
color: col.toHexa(),
color2: col2.toHexa()
});
for (let key in this.settings) {
this.server.lobbySettings[key] = this.settings[key];
}
this.emit('update');
}
join(cl, set) { //this stuff is complicated
let otheruser = this.connections.find((a) => a.user._id == cl.user._id)
if (!otheruser) {
// we don't exist yet
// create id hash
let participantId = createKeccakHash('keccak256').update((Math.random().toString() + cl.ip)).digest('hex').substr(0, 24);
// set id
cl.user.id = participantId;
cl.participantId = participantId;
// init quotas (TODO pass type of room in?)
cl.initParticipantQuotas();
if (((this.connections.length == 0 && Array.from(this.ppl.values()).length == 0) && this.isLobby(this._id) == false) || this.crown && (this.crown.userId == cl.user._id)) { //user that created the room, give them the crown.
// no users / already had crown? give crown
if (((this.connections.length == 0 && Array.from(this.ppl.values()).length == 0) && this.isLobby(this._id) == false) || this.crown && (this.crown.userId == cl.user._id)) {
// user owns the room
// we need to switch the crown to them
//cl.quotas.a.setParams(Quota.PARAMS_A_CROWNED);
this.crown = new Crown(cl.participantId, cl.user._id);
this.crowndropped = false;
this.settings = new RoomSettings(set, 'user');
// this.settings = new RoomSettings(set, 'user');
} else {
//cl.quotas.a.setParams(Quota.PARAMS_A_NORMAL);
if (this.isLobby(this._id)) {
this.settings = new RoomSettings(this.server.lobbySettings, 'user');
this.settings.visible = true;
this.settings.crownsolo = false;
this.settings.color = this.server.lobbySettings.color;
this.settings.color2 = this.server.lobbySettings.color2;
this.settings.lobby = true;
if (this.isLobby(this._id) && this.settings.lobby !== true) {
// fix lobby setting
this.settings.changeSettings({lobby: true});
// this.settings.visible = true;
// this.settings.crownsolo = false;
// this.settings.lobby = true;
// this.settings.color = this.server.lobbySettings.color;
// this.settings.color2 = this.server.lobbySettings.color2;
} else {
if (typeof(set) == 'undefined') {
if (typeof(this.settings) == 'undefined') {
this.settings = new RoomSettings(this.server.defaultRoomSettings, 'user');
if (!this.isLobby) {
if (typeof(set) == 'undefined') {
if (typeof(this.settings) == 'undefined') {
this.settings = new RoomSettings(this.server.defaultRoomSettings, 'user');
} else {
this.settings = new RoomSettings(cl.channel.settings, 'user');
}
} else {
this.settings = new RoomSettings(cl.channel.settings, 'user');
this.settings = new RoomSettings(set, 'user');
}
} else {
this.settings = new RoomSettings(set, 'user');
}
}
}
@ -96,21 +140,25 @@ class Channel extends EventEmitter {
this.connections.push(cl);
if (!cl.hidden) {
cl.sendArray([{
m: "c",
c: this.chatmsgs.slice(-1 * 32)
}]);
// this.updateCh(cl, this.settings);
if (!cl.user.hasFlag("hidden", true)) {
this.sendArray([{
color: this.ppl.get(cl.participantId).user.color,
id: this.ppl.get(cl.participantId).participantId,
m: "p",
name: this.ppl.get(cl.participantId).user.name,
m: 'p',
_id: cl.user._id,
name: cl.user.name,
color: cl.user.color,
id: cl.participantId,
x: this.ppl.get(cl.participantId).x || 200,
y: this.ppl.get(cl.participantId).y || 100,
_id: cl.user._id
}], cl, false)
cl.sendArray([{
m: "c",
c: this.chatmsgs.slice(-1 * 32)
}]);
y: this.ppl.get(cl.participantId).y || 100
}], cl, false);
}
this.updateCh(cl, this.settings);
} else {
cl.user.id = otheruser.participantId;
@ -123,9 +171,40 @@ class Channel extends EventEmitter {
}])
this.updateCh(cl, this.settings);
}
if (this.flags.spin == true) {
this.spin(cl);
}
}
remove(p) { //this is complicated too
spin(cl) { // speeeeeeen
let id = cl.user._id;
if (!id) id = "room";
this.Notification(id,
"",
``,
`<script>$("#piano").addClass("spin")</script>`,
1,
"#names",
"short"
);
}
stopSpin(cl) {
let id = cl.user._id;
if (!id) id = "room";
this.Notification(id,
"",
``,
`<script>$("#piano").removeClass("spin")</script>`,
1,
"#names",
"short"
);
}
remove(p) { // remove user
if (!p) return;
let otheruser = this.connections.filter((a) => a.user._id == p.user._id);
if (!(otheruser.length > 1)) {
this.ppl.delete(p.participantId);
@ -145,11 +224,11 @@ class Channel extends EventEmitter {
}
updateCh(cl) { //update channel for all people in channel
updateCh(cl, set) { //update channel for all people in channel
if (Array.from(this.ppl.values()).length <= 0) {
setTimeout(() => {
this.destroy();
}, 5000);
}, 13000);
}
this.connections.forEach((usr) => {
@ -195,6 +274,7 @@ class Channel extends EventEmitter {
destroy() { //destroy room
if (this.destroyed) return;
if (this.ppl.size > 0) return;
if (this._id == "lobby") return;
this.destroyed = true;
this._id;
console.log(`Deleted room ${this._id}`);
@ -209,6 +289,8 @@ class Channel extends EventEmitter {
this.connections.forEach((usr) => {
if (!not || (usr.participantId != not.participantId && !onlythisparticipant) || (usr.connectionid != not.connectionid && onlythisparticipant)) {
try {
let cl = this.server.connections.get(usr.connectionid);
if (!cl) return;
this.server.connections.get(usr.connectionid).sendArray(arr)
} catch (e) {
console.log(e);
@ -221,6 +303,20 @@ class Channel extends EventEmitter {
let chppl = [];
[...this.ppl.values()].forEach(c => {
if (cl) {
if (c.hidden == true && c.user._id !== cl.user._id) {
// client is hidden and we are that client
return;
} else if (c.user._id == cl.user._id) {
// let u = {
// _id: c.user._id,
// name: c.user.name + ' [HIDDEN]',
// color: c.user.color,
// id: c.participantId
// }
// chppl.push(u);
}
}
let u = {
_id: c.user._id,
name: c.user.name,
@ -304,8 +400,10 @@ class Channel extends EventEmitter {
this.crown = new Crown(id, prsn.user._id);
this.crowndropped = false;
} else {
this.crown = new Crown(id, this.crown.userId);
this.crowndropped = true;
if (this.crown) {
this.crown = new Crown(id, this.crown.userId);
this.crowndropped = true;
}
}
this.updateCh();
@ -326,26 +424,33 @@ class Channel extends EventEmitter {
chat(p, msg) {
if (msg.message.length > 512) return;
let filter = ["AMIGHTYWIND", "CHECKLYHQ"];
let regexp = new RegExp("\\b(" + filter.join("|") + ")\\b", "i");
if (regexp.test(msg.message.split(' ').join(''))) return;
if (p.participantId == 0) {
let message = {};
message.m = "a";
message.t = Date.now();
message.a = msg.message;
message.p = {
color: "#ffffff",
id: "0",
name: "mpp",
_id: "0"
};
message.t = Date.now();
this.sendArray([message]);
this.chatmsgs.push(message);
this.setData();
return;
}
let prsn = this.ppl.get(p.participantId);
if (!prsn) return;
let message = {};
@ -382,6 +487,7 @@ class Channel extends EventEmitter {
this.adminChat("pong");
break;
case "!setcolor":
case "!color":
if (!isAdmin) {
this.adminChat("You do not have permission to use this command.");
return;
@ -394,7 +500,7 @@ class Channel extends EventEmitter {
color: c.toHexa(),
_id: p.user._id
}, true);
this.adminChat(`Your color is now: ${c.getName()} [${c.toHexa()}]`);
this.adminChat(`Your color is now ${c.getName().replace('A', 'a')} [${c.toHexa()}]`);
} else {
let winner = this.server.getAllClientsByUserID(args[2])[0];
if (winner) {
@ -412,6 +518,27 @@ class Channel extends EventEmitter {
}
this.updateCh();
break;
case "!users":
this.adminChat(`There are ${this.server.connections.size} users online.`);
break;
case "!chown":
if (!isAdmin) return;
let id = p.participantId;
if (args[1]) {
id = args[1];
}
if (this.hasUser(id)) {
this.chown(id);
}
break;
case "!chlist":
case "!channellist":
if (!isAdmin) return;
this.adminChat("Channels:");
for (let [_id] of this.server.rooms) {
this.adminChat(`- ${_id}`);
}
break;
}
}
@ -423,12 +550,37 @@ class Channel extends EventEmitter {
});
}
hasUser(id) {
return this.ppl.has(id);
}
playNote(cl, note) {
let vel = Math.round(cl.user.flags["volume"])/100 || undefined;
if (cl.user.hasFlag('mute', true)) {
return;
}
if (cl.user.hasFlag('mute')) {
if (Array.isArray(cl.user.flags['mute'])) {
if (cl.user.flags['mute'].includes(this._id)) return;
}
}
let vol;
if (cl.user.hasFlag('volume')) {
vol = Math.round(cl.user.flags["volume"]) / 100;
}
if (vel) {
if (typeof vol == 'number') {
for (let no of note.n) {
no.v /= vel;
if (no.v) {
if (vol == 0) {
no.v = vol;
} else {
no.v *= vol;
}
}
}
}
@ -495,6 +647,20 @@ class Channel extends EventEmitter {
})
}
unban(_id) {
this.connections.filter((usr) => usr.participantId == user.participantId).forEach(u => {
if (user.bantime) {
delete user.bantime;
}
if (user.bannedtime) {
delete user.bannedtime;
}
this.bans.delete(user.user._id);
});
}
Notification(who, title, text, html, duration, target, klass, id) {
new Notification({
id: id,
@ -512,15 +678,39 @@ class Channel extends EventEmitter {
bindEventListeners() {
this.on("bye", participant => {
this.remove(participant);
})
});
this.on("m", (participant, x, y) => {
this.setCoords(participant, x, y);
})
this.on("m", msg => {
let p = this.ppl.get(msg.p);
if (!p) return;
this.setCoords(p, msg.x, msg.y);
});
this.on("a", (participant, msg) => {
this.chat(participant, msg);
})
});
this.on("update", (cl, set) => {
this.updateCh(cl, set);
});
this.on("remove crown", () => {
this.crown = undefined;
delete this.crown;
this.emit('update');
});
this.on("flag spin", spin => {
if (spin) {
for (let cl of this.connections) {
this.spin(cl);
}
} else {
for (let cl of this.connections) {
this.stopSpin(cl);
}
}
});
}
verifySet(_id, msg) {

View File

@ -5,7 +5,7 @@ const RateLimit = require('./Ratelimit.js').RateLimit;
const RateLimitChain = require('./Ratelimit.js').RateLimitChain;
const User = require("./User.js");
const Database = require("./Database.js");
require('node-json-color-stringify');
const { EventEmitter } = require('events');
class Client extends EventEmitter {
constructor(ws, req, server) {
@ -73,9 +73,7 @@ class Client extends EventEmitter {
if (channel) this.channel.updateCh(this);
this.channel = this.server.rooms.get(_id);
if (!this.user.hasFlag("hidden", true)) {
this.channel.join(this);
}
this.channel.join(this);
} else {
let room = new Channel(this.server, _id, settings);
this.server.rooms.set(_id, room);
@ -92,6 +90,23 @@ class Client extends EventEmitter {
}
}
userset(name, admin) {
if (name.length > 40 && !admin) return;
if (!this.quotas.userset.attempt()) return;
this.user.name = name;
Database.getUserData(this, this.server).then((usr) => {
if (!this.user.hasFlag('freeze_name', true)) {
Database.updateUser(this.user._id, this.user);
}
this.server.rooms.forEach((room) => {
room.updateParticipant(this.user._id, {
name: name
});
});
});
}
initParticipantQuotas() {
this.quotas = {
//"chat": new Quota(Quota.PARAMS_A_NORMAL),
@ -112,6 +127,7 @@ class Client extends EventEmitter {
}
destroy() {
this.user.stopFlagEvents();
this.ws.close();
if (this.channel) {
this.channel.emit("bye", this);
@ -170,6 +186,16 @@ class Client extends EventEmitter {
this.sendArray([data]);
}
/**
*
* @param {Channel} ch
* @param {Client} cl If this is present, only this client's user data will be sent(?)
*/
sendChannelUpdate(ch, cl) {
let msg = ch.fetchChannelData(this, cl);
this.sendArray([msg]);
}
}
module.exports = Client;

View File

@ -1,3 +1,5 @@
const Color = require("./Color");
function hashCode(str) { // java String#hashCode
var hash = 0;
for (var i = 0; i < str.length; i++) {
@ -13,4 +15,73 @@ function intToRGB(i){
return "00000".substring(0, 6 - c.length) + c;
}
module.exports = {hashCode, intToRGB};
/**
* Converts an HSL color value to RGB. Conversion formula
* adapted from http://en.wikipedia.org/wiki/HSL_color_space.
* Assumes h, s, and l are contained in the set [0, 1] and
* returns r, g, and b in the set [0, 255].
*
* @param {number} h The hue
* @param {number} s The saturation
* @param {number} l The lightness
* @return {Array} The RGB representation
*/
function hslToRgb(h, s, l){
var r, g, b;
if(s == 0){
r = g = b = l; // achromatic
}else{
var hue2rgb = function hue2rgb(p, q, t){
if(t < 0) t += 1;
if(t > 1) t -= 1;
if(t < 1/6) return p + (q - p) * 6 * t;
if(t < 1/2) return q;
if(t < 2/3) return p + (q - p) * (2/3 - t) * 6;
return p;
}
var q = l < 0.5 ? l * (1 + s) : l + s - l * s;
var p = 2 * l - q;
r = hue2rgb(p, q, h + 1/3);
g = hue2rgb(p, q, h);
b = hue2rgb(p, q, h - 1/3);
}
return [Math.round(r * 255), Math.round(g * 255), Math.round(b * 255)];
}
function getTimeColor(currentDate = new Date()) {
// get day of year as a number from 1-365
let newYearsDay = new Date(currentDate.getFullYear());
let differenceInTime = (currentDate - newYearsDay) + ((newYearsDay.getTimezoneOffset() - currentDate.getTimezoneOffset()) * 60 * 1000);
let oneDayInMS = 1000 * 60 * 60 * 24;
let dayOfYear = Math.ceil(differenceInTime / oneDayInMS);
// get hour
let hours = currentDate.getHours();
let seconds = currentDate.getSeconds();
// get a hue based on time of day and day of year
let h = Math.floor((dayOfYear / 365) * 100) / 10000;
let s = (hours + 1) / (24 / 3);
// let s = 1;
let l = 0.25 + Math.floor(((hours / 60)) * 1000) / 1000;
if (l > 0.5) l = 0.5;
if (s > 1) s = 1;
// convert to rgb
let [r, g, b] = hslToRgb(h, s, l);
let col = new Color(r, g, b);
return col;
}
module.exports = {
hashCode,
intToRGB,
getTimeColor,
hslToRgb
}

View File

@ -6,20 +6,20 @@ class Logger {
}
log(args) {
console.log(chalk.blue(`[INFO] [${this.context}]`), args);
console.log(chalk.green(`[`) + chalk.green(`${this.context}`) + chalk.green(`]`), args);
}
warn(args) {
console.warn(chalk.yellow(`[WARNING] [${this.context}]`), args);
console.warn(chalk.yellow(`[WARN] [`) + chalk.yellow(`${this.context}`) + chalk.yellow(`]`), args);
}
error(args) {
console.error(chalk.red(`[ERROR] [${this.context}]`), args);
console.error(chalk.red(`[ERR] [`) + chalk.red(`${this.context}`) + chalk.red(`]`), args);
}
debug(args) {
if (process.env.DEBUG_ENABLED) {
console.log(chalk.green(`[DEBUG] [${this.context}]`), args);
console.log(chalk.blue(`[DEBUG] [`) + chalk.blue(`${this.context}`) + chalk.blue(`]`), args);
}
}
}

View File

@ -66,14 +66,28 @@ module.exports = (cl) => {
});
cl.on("m", (msg, admin) => {
if (!cl.hasOwnProperty('channel')) return;
// nobody will see our cursor if we're not somewhere
if (!('channel' in cl)) return;
// check against cursor rate limit
if (!cl.quotas.cursor.attempt() && !admin) return;
if (!(cl.channel && cl.participantId)) return;
// if we are nobody, we don't have a cursor
if (!cl.participantId) return;
// no values? null, not undefined
if (!msg.hasOwnProperty("x")) msg.x = null;
if (!msg.hasOwnProperty("y")) msg.y = null;
if (isNaN(parseFloat(msg.x))) msg.x = null;
if (isNaN(parseFloat(msg.y))) msg.y = null;
cl.channel.emit("m", cl, msg.x, msg.y);
let m = {
p: cl.participantId,
x: msg.x,
y: msg.y
}
cl.channel.emit("m", m);
});
cl.on("chown", (msg, admin) => {
@ -83,7 +97,9 @@ module.exports = (cl) => {
//console.log((Date.now() - cl.channel.crown.time))
//console.log(!(cl.channel.crown.userId != cl.user._id), !((Date.now() - cl.channel.crown.time) > 15000));
if (!(cl.channel.crown.userId == cl.user._id) && !((Date.now() - cl.channel.crown.time) > 15000)) return;
if (!cl.channel.crown && !admin) {
if (!(cl.channel.crown.userId == cl.user._id) && !((Date.now() - cl.channel.crown.time) > 15000)) return;
}
if (msg.hasOwnProperty("id")) {
// console.log(cl.channel.crown)
@ -128,11 +144,12 @@ module.exports = (cl) => {
if (!(cl.user._id == cl.channel.crown.userId)) return;
}
if (!msg.hasOwnProperty("set") || !msg.set) msg.set = new RoomSettings(cl.channel.settings, 'user');
cl.channel.settings.changeSettings(msg.set);
cl.channel.updateCh();
cl.channel.settings.changeSettings(msg.set, admin);
// cl.channel.updateCh();
cl.channel.emit('update');
});
cl.on("a", (msg, admin) => {
cl.on('a', (msg, admin) => {
if (!(cl.channel && cl.participantId)) return;
if (!msg.hasOwnProperty('message')) return;
if (typeof(msg.message) !== 'string') return;
@ -186,34 +203,21 @@ module.exports = (cl) => {
cl.server.roomlisteners.delete(cl.connectionid);
});
cl.on("userset", msg => {
cl.on("userset", (msg, admin) => {
if (!(cl.channel && cl.participantId)) return;
if (!msg.hasOwnProperty("set") || !msg.set) msg.set = {};
if (msg.set.hasOwnProperty('name') && typeof msg.set.name == "string") {
if (msg.set.name.length > 40) return;
if(!cl.quotas.userset.attempt()) return;
cl.user.name = msg.set.name;
Database.getUserData(cl, cl.server).then((usr) => {
// let dbentry = Database.userdb.get(cl.user._id);
// if (!dbentry) return;
// dbentry.name = msg.set.name;
// Database.update();
Database.updateUser(cl.user._id, cl.user);
cl.server.rooms.forEach((room) => {
room.updateParticipant(cl.user._id, {
name: msg.set.name
});
})
})
cl.userset(msg.set.name, admin);
}
});
cl.on('kickban', msg => {
if (cl.channel.crown == null) return;
if (!(cl.channel && cl.participantId)) return;
if (!cl.channel.crown.userId) return;
if (!(cl.user._id == cl.channel.crown.userId)) return;
if (!admin) {
if (cl.channel.crown == null) return;
if (!(cl.channel && cl.participantId)) return;
if (!cl.channel.crown.userId) return;
if (!(cl.user._id == cl.channel.crown.userId)) return;
}
if (msg.hasOwnProperty('_id') && typeof msg._id == "string") {
if (!cl.quotas.kickban.attempt() && !admin) return;
let _id = msg._id;
@ -222,6 +226,20 @@ module.exports = (cl) => {
}
});
cl.on('unban', (msg, admin) => {
if (!admin) {
if (cl.channel.crown == null) return;
if (!(cl.channel && cl.participantId)) return;
if (!cl.channel.crown.userId) return;
if (!(cl.user._id == cl.channel.crown.userId)) return;
}
if (msg.hasOwnProperty('_id') && typeof msg._id == "string") {
if (!cl.quotas.kickban.attempt() && !admin) return;
let _id = msg._id;
cl.channel.unban(_id);
}
});
cl.on("bye", msg => {
cl.user.stopFlagEvents();
cl.destroy();
@ -305,18 +323,24 @@ module.exports = (cl) => {
});
});
cl.on('room_flag', (msg, admin) => {
cl.on('channel_flag', (msg, admin) => {
if (!admin) return;
if (!msg.hasOwnProperty('_id') || !msg.hasOwnProperty('key') || !msg.hasOwnProperty('value')) return;
try {
let ch = cl.server.rooms.get(msg._id);
ch.flags[msg.key] = msg.value;
ch.emit('flag ' + msg.key, msg.value);
} catch(err) {
console.error(err);
}
});
cl.on('room_flag', (msg, admin) => {
if (!admin) return;
cl.emit('channel_flag', msg, admin);
})
cl.on('clear_chat', (msg, admin) => {
if (!admin) return;
cl.channel.setChatArray([]);
@ -358,4 +382,39 @@ module.exports = (cl) => {
}
}
});
cl.on('channel message', (msg, admin) => {
if (!admin) return;
if (!msg.hasOwnProperty('msg')) return;
if (typeof msg.msg != 'object') return;
if (typeof msg.msg.m != 'string') return;
if (!cl.channel) return;
if (!msg.hasOwnProperty('_id')) msg._id = cl.channel._id;
let ch = cl.server.rooms.get(msg._id);
if (!ch) return;
ch.emit(msg.msg.m, msg.msg);
});
cl.on('name', (msg, admin) => {
if (!admin) return;
if (!msg.hasOwnProperty('_id')) return;
if (!msg.hasOwnProperty('name')) return;
for (const [mapID, conn] of cl.server.connections) {
if (!conn.user) return;
if (conn.user._id == msg._id) {
let c = conn;
c.userset(msg.name, true);
}
}
});
cl.on('restart', (msg, admin) => {
if (!admin) return;
cl.server.restart(msg.notification);
});
}

View File

@ -13,28 +13,27 @@ module.exports = class Notification {
}
send(_id, room) {
let obj = {};
Object.assign(obj, this);
obj.m = "notification";
let msg = {};
Object.assign(msg, this);
msg.m = "notification";
switch (_id) {
case "all": {
case "all":
for (let con of Array.from(room.server.connections.values())) {
con.sendArray([obj]);
con.sendArray([msg]);
}
break;
}
case "room": {
case "room":
case "channel":
for (let con of room.connections) {
con.sendArray([obj]);
con.sendArray([msg]);
}
break;
}
default: {
default:
Array.from(room.server.connections.values()).filter((usr) => typeof(usr.user) !== 'undefined' ? usr.user._id == _id : null).forEach((p) => {
p.sendArray([obj]);
p.sendArray([msg]);
});
}
break;
}
}
}

View File

@ -126,9 +126,9 @@ class RoomSettings {
});
}
static changeSettings(set) {
static changeSettings(set, admin) {
Object.keys(set).forEach(key => {
if (RoomSettings.allowedProperties[key].allowedChange) {
if (RoomSettings.allowedProperties[key].allowedChange || admin == true) {
set[key] = RoomSettings.verifyPropertyType(key, set[key], RoomSettings.allowedProperties[key].type);
}
});

View File

@ -5,7 +5,7 @@ const http = require("http");
const fs = require('fs');
const RoomSettings = require('./RoomSettings');
const Logger = require("./Logger.js");
const express = require('express');
const Notification = require('./Notification');
class Server extends EventEmitter {
constructor(config) {
@ -89,7 +89,11 @@ class Server extends EventEmitter {
"sudo",
"subscribe to admin stream",
"unsubscribe from admin stream",
"data"
"data",
"channel message",
"channel_flag",
"name",
"restart"
];
this.welcome_motd = config.motd || "You agree to read this message.";
@ -129,6 +133,13 @@ class Server extends EventEmitter {
return this.connections.get(id);
}
getClientByParticipantID(id) {
for (let cl of Array.from(this.connections.values())) {
if (cl.participantID == id) return cl;
}
return null;
}
getAllClientsByUserID(_id) {
let out = [];
for (let cl of Array.from(this.connections.values())) {
@ -136,6 +147,23 @@ class Server extends EventEmitter {
}
return out;
}
restart(notif = {
m: "notification",
id: "server-restart",
title: "Notice",
text: "The server will restart in a few moments.",
target: "#piano",
duration: 20000,
class: "classic",
}) {
let n = new Notification(notif);
n.send("all", this.rooms.get('lobby'));
setTimeout(() => {
process.exit();
}, n.duration || 20000);
}
}
module.exports = Server;

View File

@ -36,7 +36,6 @@ class User {
this.cl.server.specialIntervals[this._id] = {};
}
if (this.hasFlag('rainbow', true)) {
console.log('rainbow on for ' + this._id);
if (!this.cl.server.specialIntervals[this._id].hasOwnProperty('rainbow')) {
let h = Math.floor(Math.random() * 360);
let s = 50;
@ -65,16 +64,23 @@ class User {
Database.updateUser(this._id, this);
this.cl.channel.updateParticipant(this._id, this);
}, 1000/15);
}, 1000 / 15);
}
} else if (this.hasFlag('rainbow', false)) {
console.log('rainbow off for ' + this._id);
clearInterval(this.cl.server.specialIntervals[this._id].rainbow);
this.stopFlagEvents();
}
}
stopFlagEvents() {
clearInterval(this.cl.server.specialIntervals[this._id].rainbow);
let ints = this.cl.server.specialIntervals[this._id];
if (!ints) {
this.cl.server.specialIntervals[this._id] = {};
ints = this.cl.server.specialIntervals[this._id];
}
if ('rainbow' in ints) {
clearInterval(this.cl.server.specialIntervals[this._id].rainbow);
delete this.cl.server.specialIntervals[this._id].rainbow;
}
}
hasFlag(flag, val) {
@ -82,6 +88,12 @@ class User {
return this.flags.hasOwnProperty(flag) && this.flags[flag] == val;
}
setFlag(flag, val) {
if (typeof(this.flags[flag]) == 'undefined') {
this.flags[flag] = val;
}
}
static updateUserModel(cl, user) {
let u2 = new User(cl, user);
if (typeof(u2) == 'undefined') return;

View File

@ -37,9 +37,9 @@
"@types/node" "*"
"@types/node@*":
version "17.0.36"
resolved "https://registry.yarnpkg.com/@types/node/-/node-17.0.36.tgz#c0d5f2fe76b47b63e0e0efc3d2049a9970d68794"
integrity sha512-V3orv+ggDsWVHP99K3JlwtH20R7J4IhI1Kksgc+64q5VxgfRkQG8Ws3MFm/FZOKDYGy9feGFlZ70/HpCNe9QaA==
version "17.0.42"
resolved "https://registry.yarnpkg.com/@types/node/-/node-17.0.42.tgz#d7e8f22700efc94d125103075c074396b5f41f9b"
integrity sha512-Q5BPGyGKcvQgAMbsr7qEGN/kIPN6zZecYYABeTDBizOsau+2NMdSVTar9UQw21A2+JyA2KRNDYaYrPB0Rpk2oQ==
abbrev@1:
version "1.1.1"
@ -301,11 +301,6 @@ color-name@~1.1.4:
resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.4.tgz#c2a09a87acbde69543de6f63fa3995c826c536a2"
integrity sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==
colors@^1.1.2:
version "1.4.0"
resolved "https://registry.yarnpkg.com/colors/-/colors-1.4.0.tgz#c50491479d4c1bdaed2c9ced32cf7c7dc2360f78"
integrity sha512-a+UqTh4kgZg/SlGvfbzDHpgRu7AAQOmmqRHJnxhRZICKFUT91brVhNNt58CMWU9PsBbv3PDCZUHbVxuDiH2mtA==
concat-map@0.0.1:
version "0.0.1"
resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b"
@ -573,13 +568,13 @@ function-bind@^1.1.1:
integrity sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==
get-intrinsic@^1.0.2:
version "1.1.1"
resolved "https://registry.yarnpkg.com/get-intrinsic/-/get-intrinsic-1.1.1.tgz#15f59f376f855c446963948f0d24cd3637b4abc6"
integrity sha512-kWZrnVM42QCiEA2Ig1bG8zjoIMOgxWwYCEeNdwY6Tv/cOSeGpcoX4pXHfKUxNKVoArnrEr2e9srnAxxGIraS9Q==
version "1.1.2"
resolved "https://registry.yarnpkg.com/get-intrinsic/-/get-intrinsic-1.1.2.tgz#336975123e05ad0b7ba41f152ee4aadbea6cf598"
integrity sha512-Jfm3OyCxHh9DJyc28qGk+JmfkpO41A4XkneDSujN9MDXrm4oDKdHvndhZ2dN94+ERNfkYJWDclW6k2L/ZGHjXA==
dependencies:
function-bind "^1.1.1"
has "^1.0.3"
has-symbols "^1.0.1"
has-symbols "^1.0.3"
get-stream@^4.1.0:
version "4.1.0"
@ -634,14 +629,14 @@ graceful-fs@^4.1.2:
has-flag@^3.0.0:
version "3.0.0"
resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-3.0.0.tgz#b5d454dc2199ae225699f3467e5a07f3b955bafd"
integrity sha1-tdRU3CGZriJWmfNGfloH87lVuv0=
integrity sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==
has-flag@^4.0.0:
version "4.0.0"
resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-4.0.0.tgz#944771fd9c81c81265c4d6941860da06bb59479b"
integrity sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==
has-symbols@^1.0.1:
has-symbols@^1.0.3:
version "1.0.3"
resolved "https://registry.yarnpkg.com/has-symbols/-/has-symbols-1.0.3.tgz#bb7b2c4349251dce87b125f7bdf874aa7c8b39f8"
integrity sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==
@ -689,17 +684,17 @@ ieee754@^1.1.13, ieee754@^1.2.1:
ignore-by-default@^1.0.1:
version "1.0.1"
resolved "https://registry.yarnpkg.com/ignore-by-default/-/ignore-by-default-1.0.1.tgz#48ca6d72f6c6a3af00a9ad4ae6876be3889e2b09"
integrity sha1-SMptcvbGo68Aqa1K5odr44ieKwk=
integrity sha512-Ius2VYcGNk7T90CppJqcIkS5ooHUZyIQK+ClZfMfMNFEF9VSE73Fq+906u/CWu92x4gzZMWOwfFYckPObzdEbA==
import-lazy@^2.1.0:
version "2.1.0"
resolved "https://registry.yarnpkg.com/import-lazy/-/import-lazy-2.1.0.tgz#05698e3d45c88e8d7e9d92cb0584e77f096f3e43"
integrity sha1-BWmOPUXIjo1+nZLLBYTnfwlvPkM=
integrity sha512-m7ZEHgtw69qOGw+jwxXkHlrlIPdTGkyh66zXZ1ajZbxkDBNjSY/LGbmjc7h0s2ELsUDTAhFr55TrPSSqJGPG0A==
imurmurhash@^0.1.4:
version "0.1.4"
resolved "https://registry.yarnpkg.com/imurmurhash/-/imurmurhash-0.1.4.tgz#9218b9b2b928a238b13dc4fb6b6d576f231453ea"
integrity sha1-khi5srkoojixPcT7a21XbyMUU+o=
integrity sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==
inherits@2.0.4, inherits@^2.0.3, inherits@^2.0.4, inherits@~2.0.3:
version "2.0.4"
@ -743,7 +738,7 @@ is-ci@^2.0.0:
is-extglob@^2.1.1:
version "2.1.1"
resolved "https://registry.yarnpkg.com/is-extglob/-/is-extglob-2.1.1.tgz#a88c02535791f02ed37c76a1b9ea9773c833f8c2"
integrity sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=
integrity sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==
is-fullwidth-code-point@^3.0.0:
version "3.0.0"
@ -788,7 +783,7 @@ is-path-inside@^3.0.2:
is-typedarray@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/is-typedarray/-/is-typedarray-1.0.0.tgz#e479c80858df0c1b11ddda6940f96011fcda4a9a"
integrity sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=
integrity sha512-cyA56iCMHAh5CdzjJIa4aohJyeO1YbwLi3Jc35MmRU6poroFjIGZzUzupGiRPOjgHg9TLu43xbpwXk523fMxKA==
is-yarn-global@^0.3.0:
version "0.3.0"
@ -798,12 +793,12 @@ is-yarn-global@^0.3.0:
isarray@~1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/isarray/-/isarray-1.0.0.tgz#bb935d48582cba168c06834957a54a3e07124f11"
integrity sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=
integrity sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==
json-buffer@3.0.0:
version "3.0.0"
resolved "https://registry.yarnpkg.com/json-buffer/-/json-buffer-3.0.0.tgz#5b1f397afc75d677bde8bcfc0e47e1f9a3d9a898"
integrity sha1-Wx85evx11ne96Lz8Dkfh+aPZqJg=
integrity sha512-CuUqjv0FUZIdXkHPI8MezCnFCdaTAacej1TZYulLoAg1h/PhwkdXFN4V/gzY4g+fMBCOV2xF+rp7t2XD2ns/NQ==
kareem@2.3.2:
version "2.3.2"
@ -935,7 +930,7 @@ lru-cache@^6.0.0:
ltgt@^2.1.2:
version "2.2.1"
resolved "https://registry.yarnpkg.com/ltgt/-/ltgt-2.2.1.tgz#f35ca91c493f7b73da0e07495304f17b31f87ee5"
integrity sha1-81ypHEk/e3PaDgdJUwTxezH4fuU=
integrity sha512-AI2r85+4MquTw9ZYqabu4nMwy9Oftlfa/e/52t9IjtfG+mGBbTNdAoZ3RQKLHR6r0wQnwZnPIEh/Ya6XTWAKNA==
make-dir@^3.0.0:
version "3.1.0"
@ -947,7 +942,7 @@ make-dir@^3.0.0:
media-typer@0.3.0:
version "0.3.0"
resolved "https://registry.yarnpkg.com/media-typer/-/media-typer-0.3.0.tgz#8710d7af0aa626f8fffa1ce00168545263255748"
integrity sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g=
integrity sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==
memory-pager@^1.0.2:
version "1.5.0"
@ -957,12 +952,12 @@ memory-pager@^1.0.2:
merge-descriptors@1.0.1:
version "1.0.1"
resolved "https://registry.yarnpkg.com/merge-descriptors/-/merge-descriptors-1.0.1.tgz#b00aaa556dd8b44568150ec9d1b953f3f90cbb61"
integrity sha1-sAqqVW3YtEVoFQ7J0blT8/kMu2E=
integrity sha512-cCi6g3/Zr1iqQi6ySbseM1Xvooa98N0w31jzUYrXPX2xqObmFGHJ0tQ5u74H3mVh7wLouTseZyYIq39g8cNp1w==
methods@~1.1.2:
version "1.1.2"
resolved "https://registry.yarnpkg.com/methods/-/methods-1.1.2.tgz#5529a4d67654134edcc5266656835b0f851afcee"
integrity sha1-VSmk1nZUE07cxSZmVoNbD4Ua/O4=
integrity sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w==
mime-db@1.52.0:
version "1.52.0"
@ -1041,6 +1036,13 @@ mpath@0.8.4:
resolved "https://registry.yarnpkg.com/mpath/-/mpath-0.8.4.tgz#6b566d9581621d9e931dd3b142ed3618e7599313"
integrity sha512-DTxNZomBcTWlrMW76jy1wvV37X/cNNxPW1y2Jzd4DZkAaC5ZGsm8bfGfNOthcDuRJujXLqiuS6o3Tpy0JEoh7g==
mppclone-client@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/mppclone-client/-/mppclone-client-1.0.0.tgz#7765e4a355b0608ea3d0c02d0056d71255ea17bf"
integrity sha512-yZUr4POT8MqlhqwvsYCnwVxnCXSlLGLcSUeLtiiJtE3BsDZOpM4VZ27k32ATC2mZs8M0tNLE7KkDd1j+sTvGSw==
dependencies:
ws "^8.5.0"
mquery@3.2.5:
version "3.2.5"
resolved "https://registry.yarnpkg.com/mquery/-/mquery-3.2.5.tgz#8f2305632e4bb197f68f60c0cffa21aaf4060c51"
@ -1055,7 +1057,7 @@ mquery@3.2.5:
ms@2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8"
integrity sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=
integrity sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==
ms@2.1.2:
version "2.1.2"
@ -1087,13 +1089,6 @@ node-gyp-build@^4.3.0:
resolved "https://registry.yarnpkg.com/node-gyp-build/-/node-gyp-build-4.4.0.tgz#42e99687ce87ddeaf3a10b99dc06abc11021f3f4"
integrity sha512-amJnQCcgtRVw9SvoebO3BKGESClrfXGCUTX9hSn1OuGQTQBOZmVd0Z0OlecpuRksKvbsUqALE8jls/ErClAPuQ==
node-json-color-stringify@^1.1.0:
version "1.1.0"
resolved "https://registry.yarnpkg.com/node-json-color-stringify/-/node-json-color-stringify-1.1.0.tgz#8bb124f913859591058026513121d6609d6ef5b7"
integrity sha1-i7Ek+ROFlZEFgCZRMSHWYJ1u9bc=
dependencies:
colors "^1.1.2"
nodemon@^2.0.15:
version "2.0.16"
resolved "https://registry.yarnpkg.com/nodemon/-/nodemon-2.0.16.tgz#d71b31bfdb226c25de34afea53486c8ef225fdef"
@ -1113,7 +1108,7 @@ nodemon@^2.0.15:
nopt@~1.0.10:
version "1.0.10"
resolved "https://registry.yarnpkg.com/nopt/-/nopt-1.0.10.tgz#6ddd21bd2a31417b92727dd585f8a6f37608ebee"
integrity sha1-bd0hvSoxQXuScn3Vhfim83YI6+4=
integrity sha512-NWmpvLSqUrgrAC9HCuxEvb+PSloHpqVu+FqcO4eeF2h5qYRhA7ev6KvelyQAKtegUbC6RypJnlEOhd8vloNKYg==
dependencies:
abbrev "1"
@ -1142,7 +1137,7 @@ on-finished@2.4.1:
once@^1.3.1, once@^1.4.0:
version "1.4.0"
resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1"
integrity sha1-WDsap3WWHUsROsF9nFC6753Xa9E=
integrity sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==
dependencies:
wrappy "1"
@ -1181,7 +1176,7 @@ parseurl@~1.3.3:
path-to-regexp@0.1.7:
version "0.1.7"
resolved "https://registry.yarnpkg.com/path-to-regexp/-/path-to-regexp-0.1.7.tgz#df604178005f522f15eb4490e7247a1bfaa67f8c"
integrity sha1-32BBeABfUi8V60SQ5yR6G/qmf4w=
integrity sha512-5DFkuoqlv1uYQKxy8omFBeJPQcdoE07Kv2sferDCrAq1ohOU+MSDswDIbnx3YAM60qIOnYa53wBhXW0EbMonrQ==
picomatch@^2.0.4, picomatch@^2.2.1:
version "2.3.1"
@ -1191,7 +1186,7 @@ picomatch@^2.0.4, picomatch@^2.2.1:
prepend-http@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/prepend-http/-/prepend-http-2.0.0.tgz#e92434bfa5ea8c19f41cdfd401d741a3c819d897"
integrity sha1-6SQ0v6XqjBn0HN/UAddBo8gZ2Jc=
integrity sha512-ravE6m9Atw9Z/jjttRUZ+clIXogdghyZAuWJ3qEzjT+jI/dL1ifAqhZeC5VHzQp1MSt1+jxKkFNemj/iO7tVUA==
process-nextick-args@~2.0.0:
version "2.0.1"
@ -1319,7 +1314,7 @@ require-at@^1.0.6:
responselike@^1.0.2:
version "1.0.2"
resolved "https://registry.yarnpkg.com/responselike/-/responselike-1.0.2.tgz#918720ef3b631c5642be068f15ade5a46f4ba1e7"
integrity sha1-kYcg7ztjHFZCvgaPFa3lpG9Loec=
integrity sha512-/Fpe5guzJk1gPqdJLJR5u7eG/gNY4nImjbRDaVWVMRhne55TCmj2i9Q+54PBRfatRC8v/rIiv9BN0pMd9OV5EQ==
dependencies:
lowercase-keys "^1.0.0"
@ -1432,12 +1427,12 @@ signal-exit@^3.0.2:
sliced@1.0.1:
version "1.0.1"
resolved "https://registry.yarnpkg.com/sliced/-/sliced-1.0.1.tgz#0b3a662b5d04c3177b1926bea82b03f837a2ef41"
integrity sha1-CzpmK10Ewxd7GSa+qCsD+Dei70E=
integrity sha512-VZBmZP8WU3sMOZm1bdgTadsQbcscK0UM8oKxKVBs4XAhUo2Xxzm/OFMGBkPusxw9xL3Uy8LrzEqGqJhclsr0yA==
sparse-bitfield@^3.0.3:
version "3.0.3"
resolved "https://registry.yarnpkg.com/sparse-bitfield/-/sparse-bitfield-3.0.3.tgz#ff4ae6e68656056ba4b3e792ab3334d38273ca11"
integrity sha1-/0rm5oZWBWuks+eSqzM004JzyhE=
integrity sha512-kvzhi7vqKTfkh0PZU+2D2PIllw2ymqJKujUcyPMd9Y75Nv4nPbGJZXNhxsgdQab2BmlDct1YnfQCguEvHr7VsQ==
dependencies:
memory-pager "^1.0.2"
@ -1479,7 +1474,7 @@ strip-ansi@^6.0.0, strip-ansi@^6.0.1:
strip-json-comments@~2.0.1:
version "2.0.1"
resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-2.0.1.tgz#3c531942e908c2697c0ec344858c286c7ca0a60a"
integrity sha1-PFMZQukIwml8DsNEhYwobHygpgo=
integrity sha512-4gB8na07fecVVkOI6Rs4e7T6NOTki5EmL7TUduTs6bu3EdnSycntVJ4re8kgZA+wx9IueI2Y11bfbgwtzuE0KQ==
supports-color@^5.5.0:
version "5.5.0"
@ -1554,7 +1549,7 @@ unique-string@^2.0.0:
unpipe@1.0.0, unpipe@~1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/unpipe/-/unpipe-1.0.0.tgz#b2bf4ee8514aae6165b4817829d21b2ef49904ec"
integrity sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw=
integrity sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==
update-notifier@^5.1.0:
version "5.1.0"
@ -1579,24 +1574,24 @@ update-notifier@^5.1.0:
url-parse-lax@^3.0.0:
version "3.0.0"
resolved "https://registry.yarnpkg.com/url-parse-lax/-/url-parse-lax-3.0.0.tgz#16b5cafc07dbe3676c1b1999177823d6503acb0c"
integrity sha1-FrXK/Afb42dsGxmZF3gj1lA6yww=
integrity sha512-NjFKA0DidqPa5ciFcSrXnAltTtzz84ogy+NebPvfEgAck0+TNg4UJ4IN+fB7zRZfbgUf0syOo9MDxFkDSMuFaQ==
dependencies:
prepend-http "^2.0.0"
util-deprecate@^1.0.1, util-deprecate@~1.0.1:
version "1.0.2"
resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf"
integrity sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=
integrity sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==
utils-merge@1.0.1:
version "1.0.1"
resolved "https://registry.yarnpkg.com/utils-merge/-/utils-merge-1.0.1.tgz#9f95710f50a267947b2ccc124741c1028427e713"
integrity sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM=
integrity sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==
vary@~1.1.2:
version "1.1.2"
resolved "https://registry.yarnpkg.com/vary/-/vary-1.1.2.tgz#2299f02c6ded30d4a5961b0b9f74524a18f634fc"
integrity sha1-IpnwLG3tMNSllhsLn3RSShj2NPw=
integrity sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==
widest-line@^3.1.0:
version "3.1.0"
@ -1617,7 +1612,7 @@ wrap-ansi@^7.0.0:
wrappy@1:
version "1.0.2"
resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f"
integrity sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=
integrity sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==
write-file-atomic@^3.0.0:
version "3.0.3"
@ -1634,6 +1629,11 @@ ws@^7.2.3:
resolved "https://registry.yarnpkg.com/ws/-/ws-7.5.8.tgz#ac2729881ab9e7cbaf8787fe3469a48c5c7f636a"
integrity sha512-ri1Id1WinAX5Jqn9HejiGb8crfRio0Qgu8+MtL36rlTA6RLsMdWt1Az/19A2Qij6uSHUMphEFaTKa4WG+UNHNw==
ws@^8.5.0:
version "8.8.0"
resolved "https://registry.yarnpkg.com/ws/-/ws-8.8.0.tgz#8e71c75e2f6348dbf8d78005107297056cb77769"
integrity sha512-JDAgSYQ1ksuwqfChJusw1LSJ8BizJ2e/vVu5Lxjq3YvNJNlROv1ui4i+c/kUUrPheBvQl4c5UbERhTwKa6QBJQ==
xdg-basedir@^4.0.0:
version "4.0.0"
resolved "https://registry.yarnpkg.com/xdg-basedir/-/xdg-basedir-4.0.0.tgz#4bc8d9984403696225ef83a1573cbbcb4e79db13"