From 67a016e0c9a17f6f28cf23a45b24b1218f06e43b Mon Sep 17 00:00:00 2001 From: Chars chan Date: Thu, 29 Aug 2019 17:27:30 -0600 Subject: [PATCH 001/135] Add package.json --- package.json | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) create mode 100644 package.json diff --git a/package.json b/package.json new file mode 100644 index 0000000..7baf1f8 --- /dev/null +++ b/package.json @@ -0,0 +1,24 @@ +{ + "name": "mpp-server-master", + "version": "1.0.0", + "description": "Attempt at making a MPP Server.", + "main": "index.js", + "scripts": { + "test": "echo \"Error: no test specified\" && exit 1" + }, + "repository": { + "type": "git", + "url": "git+https://github.com/BopItFreak/mpp-server.git" + }, + "keywords": [ + "mpp", + "server", + "multiplayerpiano" + ], + "author": "BopItFreak", + "license": "ISC", + "bugs": { + "url": "https://github.com/BopItFreak/mpp-server/issues" + }, + "homepage": "https://github.com/BopItFreak/mpp-server#readme" +} From b8dfeb05d6391d9a8be2a49089a7f6e584abf041 Mon Sep 17 00:00:00 2001 From: Chars chan Date: Thu, 29 Aug 2019 17:35:39 -0600 Subject: [PATCH 002/135] Add modules --- package.json | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/package.json b/package.json index 7baf1f8..895bc77 100644 --- a/package.json +++ b/package.json @@ -20,5 +20,13 @@ "bugs": { "url": "https://github.com/BopItFreak/mpp-server/issues" }, - "homepage": "https://github.com/BopItFreak/mpp-server#readme" + "homepage": "https://github.com/BopItFreak/mpp-server#readme", + "dependencies": { + "asyncconsole": "^1.3.9", + "events": "^3.0.0", + "keccak": "^2.0.0", + "node-json-color-stringify": "^1.1.0", + "ws": "^7.1.2" + }, + "devDependencies": {} } From a078ce6ca12abaf3d80ed27469103ae7c67a01ea Mon Sep 17 00:00:00 2001 From: Chars chan <28523197+Charsy89@users.noreply.github.com> Date: Mon, 18 Nov 2019 21:17:33 -0700 Subject: [PATCH 003/135] Still send chat to user --- src/Room.js | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/Room.js b/src/Room.js index 9e4dd11..818294b 100644 --- a/src/Room.js +++ b/src/Room.js @@ -68,6 +68,10 @@ class Room extends EventEmitter { cl.user.id = otheruser.participantId; cl.participantId = otheruser.participantId; this.connections.push(cl); + cl.sendArray([{ + m: "c", + c: this.chatmsgs.slice(-1 * 32) + }]) this.updateCh(cl); } @@ -400,4 +404,4 @@ class Room extends EventEmitter { } } -module.exports = Room; \ No newline at end of file +module.exports = Room; From 1602896928aeba1a0993158c7c92276e064c2dcd Mon Sep 17 00:00:00 2001 From: Chars chan <28523197+Charsy89@users.noreply.github.com> Date: Tue, 19 Nov 2019 19:46:15 -0700 Subject: [PATCH 004/135] Use newer isLobby --- src/Room.js | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/src/Room.js b/src/Room.js index 818294b..efb0475 100644 --- a/src/Room.js +++ b/src/Room.js @@ -202,13 +202,19 @@ class Room extends EventEmitter { } isLobby(_id) { if (_id.startsWith("lobby")) { + let lobbynum = _id.split("lobby")[1]; if (_id == "lobby") { return true; - } else if (parseFloat(_id.split("lobby")[1] % 1) === 0) { - return true; - } else { - return false; - } + } + if (!(parseInt(lobbynum).toString() == lobbynum)) return false; + for (let i in lobbynum) { + if (parseInt(lobbynum[i]) >= 0) { + if (parseInt(i) + 1 == lobbynum.length) return true; + + } else { + return false; + } + } } else if (_id.startsWith("test/")) { if (_id == "test/") { return false; From ae93af21439eb2c18f388ea2c533155f7010f4e5 Mon Sep 17 00:00:00 2001 From: Charsy89 Date: Tue, 19 Nov 2019 22:08:47 -0700 Subject: [PATCH 005/135] Fix lobby creation bug --- index.js | 10 ++++++++++ src/Message.js | 11 ++--------- src/Room.js | 52 ++++++++++++++++++++++++++++---------------------- 3 files changed, 41 insertions(+), 32 deletions(-) diff --git a/index.js b/index.js index 18e9de6..62db0b2 100644 --- a/index.js +++ b/index.js @@ -5,6 +5,16 @@ global.fs = require('fs'); global.createKeccakHash = require('keccak'); const AsyncConsole = require('asyncconsole') +global.isString = function(a){ + return typeof a === 'string'; +} +global.isBool = function(a){ + return typeof a === 'boolean'; +} +global.isObj = function(a){ + return typeof a === "object" && !Array.isArray(a) && a !== null; +} + let Server = require("./src/Server.js"); let config = require('./src/db/config.json'); global.SERVER = new Server(config); diff --git a/src/Message.js b/src/Message.js index 97bcfbd..b8b79d9 100644 --- a/src/Message.js +++ b/src/Message.js @@ -55,15 +55,8 @@ module.exports = (cl) => { cl.on("chset", msg => { if (!(cl.channel && cl.participantId)) return; if (!(cl.user._id == cl.channel.crown.userId)) return; - if (!msg.hasOwnProperty("set") || !msg.set) msg.set = {}; - let settings = {}; - settings.lobby = cl.channel.isLobby(cl.channel._id); - settings.visible = !!msg.set.visible; - settings.crownsolo = !!msg.set.crownsolo; - settings.chat = !!msg.set.chat; - settings.color = cl.channel.verifyColor(msg.set.color) || cl.channel.settings.color; - settings.color2 = cl.channel.verifyColor(msg.set.color2) || cl.channel.settings.color2; - cl.channel.settings = settings; + if (!msg.hasOwnProperty("set") || !msg.set) msg.set = cl.channel.verifySet(cl.channel._id,{}); + cl.channel.settings = msg.set; cl.channel.updateCh(); }) cl.on("a", msg => { diff --git a/src/Room.js b/src/Room.js index efb0475..a3019f1 100644 --- a/src/Room.js +++ b/src/Room.js @@ -11,14 +11,7 @@ class Room extends EventEmitter { this.server = server; this.crown = null; this.crowndropped = false; - this.settings = { - lobby: this.isLobby(_id), - visible: settings.hasOwnProperty('visible') ? settings.visible : true, - crownsolo: settings.crownsolo || false, - chat: settings.chat || true, - color: this.verifyColor(settings.color) || this.getColor(_id), - color2: this.verifyColor(settings.color) || this.getColor2(_id) - } + this.settings = this.verifySet(this._id,settings); this.chatmsgs = []; this.ppl = new Map(); this.connections = []; @@ -184,21 +177,6 @@ class Room extends EventEmitter { } else{ return false; } - } - getColor(_id) { - if (this.isLobby(_id)) { - return this.server.defaultLobbyColor; - } else { - return this.server.defaultRoomColor; - } - } - getColor2(_id) { - if (this.isLobby(_id)) { - return this.server.defaultLobbyColor2; - } else { - return; - delete this.settings.color2; - } } isLobby(_id) { if (_id.startsWith("lobby")) { @@ -408,6 +386,34 @@ class Room extends EventEmitter { this.chat(participant, msg); }) } + verifySet(_id,msg){ + if(!isObj(msg.set)) msg.set = {visible:true,color:this.server.defaultRoomColor,chat:true,crownsolo:false}; + if(isBool(msg.set.lobby)){ + if(!this.isLobby(_id)) delete msg.set.lobby; // keep it nice and clean + }else{ + if(this.isLobby(_id)) msg.set = {visible:true,color:this.server.defaultLobbyColor,color2:this.server.defaultLobbyColor2,chat:true,crownsolo:false,lobby:true}; + } + if(!isBool(msg.set.visible)){ + if(msg.set.visible == undefined) msg.set.visible = (room.settings.visible || true); + else msg.set.visible = true; + }; + if(!isBool(msg.set.chat)){ + if(msg.set.chat == undefined) msg.set.chat = (room.settings.chat || true); + else msg.set.chat = true; + }; + if(!isBool(msg.set.crownsolo)){ + if(msg.set.crownsolo == undefined) msg.set.crownsolo = (room.settings.crownsolo || false); + else msg.set.crownsolo = false; + }; + if(!isString(msg.set.color) || !/^#[0-9a-f]{6}$/i.test(msg.set.color)) msg.set.color = (room.settings.color || this.server.defaultRoomColor); + if(isString(msg.set.color2)){ + if(!/^#[0-9a-f]{6}$/i.test(msg.set.color2)){ + if(room.settings.color2) msg.set.color2 = room.settings.color2; + else delete msg.set.color2; // keep it nice and clean + } + }; + return msg.set; + } } module.exports = Room; From e27484a0398ef33020accc52c5a53c2fc8761345 Mon Sep 17 00:00:00 2001 From: Charsy89 Date: Wed, 20 Nov 2019 16:11:11 -0700 Subject: [PATCH 006/135] Fix verifySet, give msg syntax --- src/Room.js | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/src/Room.js b/src/Room.js index a3019f1..e3322d5 100644 --- a/src/Room.js +++ b/src/Room.js @@ -11,7 +11,7 @@ class Room extends EventEmitter { this.server = server; this.crown = null; this.crowndropped = false; - this.settings = this.verifySet(this._id,settings); + this.settings = this.verifySet(this._id,{set:settings}); this.chatmsgs = []; this.ppl = new Map(); this.connections = []; @@ -102,7 +102,6 @@ class Room extends EventEmitter { options.name ? this.ppl.get(pid).user.name = options.name : {}; options._id ? this.ppl.get(pid).user._id = options._id : {}; options.color ? this.ppl.get(pid).user.color = options.color : {}; - options.name ? this.ppl.get(pid).user.name = options.name : {}; this.connections.filter((ofo) => ofo.participantId == p.participantId).forEach((usr) => { options.name ? usr.user.name = options.name : {}; options._id ? usr.user._id = options._id : {}; @@ -394,21 +393,21 @@ class Room extends EventEmitter { if(this.isLobby(_id)) msg.set = {visible:true,color:this.server.defaultLobbyColor,color2:this.server.defaultLobbyColor2,chat:true,crownsolo:false,lobby:true}; } if(!isBool(msg.set.visible)){ - if(msg.set.visible == undefined) msg.set.visible = (room.settings.visible || true); + if(msg.set.visible == undefined) msg.set.visible = (!isObj(this.settings) ? true : this.settings.visible); else msg.set.visible = true; }; if(!isBool(msg.set.chat)){ - if(msg.set.chat == undefined) msg.set.chat = (room.settings.chat || true); + if(msg.set.chat == undefined) msg.set.chat = (!isObj(this.settings) ? true : this.settings.chat); else msg.set.chat = true; }; if(!isBool(msg.set.crownsolo)){ - if(msg.set.crownsolo == undefined) msg.set.crownsolo = (room.settings.crownsolo || false); + if(msg.set.crownsolo == undefined) msg.set.crownsolo = (!isObj(this.settings) ? false : this.settings.crownsolo); else msg.set.crownsolo = false; }; - if(!isString(msg.set.color) || !/^#[0-9a-f]{6}$/i.test(msg.set.color)) msg.set.color = (room.settings.color || this.server.defaultRoomColor); + if(!isString(msg.set.color) || !/^#[0-9a-f]{6}$/i.test(msg.set.color)) msg.set.color = (!isObj(this.settings) ? this.server.defaultRoomColor : this.settings.color); if(isString(msg.set.color2)){ if(!/^#[0-9a-f]{6}$/i.test(msg.set.color2)){ - if(room.settings.color2) msg.set.color2 = room.settings.color2; + if(this.settings.color2) msg.set.color2 = this.settings.color2; else delete msg.set.color2; // keep it nice and clean } }; From effb568b51706cec6f167a828d9d610a63d230ec Mon Sep 17 00:00:00 2001 From: Charsy89 Date: Wed, 20 Nov 2019 16:13:20 -0700 Subject: [PATCH 007/135] gha forgot color2 --- src/Room.js | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/Room.js b/src/Room.js index e3322d5..f6f6520 100644 --- a/src/Room.js +++ b/src/Room.js @@ -407,8 +407,10 @@ class Room extends EventEmitter { if(!isString(msg.set.color) || !/^#[0-9a-f]{6}$/i.test(msg.set.color)) msg.set.color = (!isObj(this.settings) ? this.server.defaultRoomColor : this.settings.color); if(isString(msg.set.color2)){ if(!/^#[0-9a-f]{6}$/i.test(msg.set.color2)){ - if(this.settings.color2) msg.set.color2 = this.settings.color2; - else delete msg.set.color2; // keep it nice and clean + if(this.settings){ + if(this.settings.color2) msg.set.color2 = this.settings.color2; + else delete msg.set.color2; // keep it nice and clean + } } }; return msg.set; From 8d438a38daba3d59d88157c8f964d0b3ac157a71 Mon Sep 17 00:00:00 2001 From: wolfy01 <45273698+wolfy01@users.noreply.github.com> Date: Tue, 7 Apr 2020 01:59:49 -0400 Subject: [PATCH 008/135] Create Ratelimit.js --- src/Ratelimit.js | 40 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 40 insertions(+) create mode 100644 src/Ratelimit.js diff --git a/src/Ratelimit.js b/src/Ratelimit.js new file mode 100644 index 0000000..f43157d --- /dev/null +++ b/src/Ratelimit.js @@ -0,0 +1,40 @@ + +var RateLimit = function(interval_ms) { + this._interval_ms = interval_ms || 0; // (0 means no limit) + this._after = 0; +}; + +RateLimit.prototype.attempt = function(time) { + var time = time || Date.now(); + if(time < this._after) return false; + this._after = time + this._interval_ms; + return true; +}; + +RateLimit.prototype.setInterval = function(interval_ms) { + this._after += interval_ms - this._interval_ms; + this._interval_ms = interval_ms; +}; + +var RateLimitChain = function(num, interval_ms) { + this.setNumAndInterval(num, interval_ms); +}; + +RateLimitChain.prototype.attempt = function(time) { + var time = time || Date.now(); + for(var i = 0; i < this._chain.length; i++) { + if(this._chain[i].attempt(time)) return true; + } + return false; +}; + +RateLimitChain.prototype.setNumAndInterval = function(num, interval_ms) { + this._chain = []; + for(var i = 0; i < num; i++) { + this._chain.push(new RateLimit(interval_ms)); + } +}; + +var exports = typeof module !== "undefined" ? module.exports : this; +exports.RateLimit = RateLimit; +exports.RateLimitChain = RateLimitChain; From b62bb01c2b0fc60d3e1cf56dafa437e9068355fd Mon Sep 17 00:00:00 2001 From: wolfy01 <45273698+wolfy01@users.noreply.github.com> Date: Tue, 7 Apr 2020 02:01:41 -0400 Subject: [PATCH 009/135] Update Client.js --- src/Client.js | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/Client.js b/src/Client.js index c762e68..4751df9 100644 --- a/src/Client.js +++ b/src/Client.js @@ -1,3 +1,5 @@ +const RateLimit = require('./RateLimit.js').RateLimit; +const RateLimitChain = require('./RateLimit.js').RateLimitChain; const Room = require("./Room.js"); require('node-json-color-stringify'); class Client extends EventEmitter { @@ -14,6 +16,10 @@ class Client extends EventEmitter { this.ip = (req.connection.remoteAddress).replace("::ffff:", ""); this.destroied = false; this.bindEventListeners(); + this.cursQuota = new RateLimit(16); + this.chatQuota = new RateLimitChain(4, 4000); + this.nameQuota = new RateLimitChain(30, 30 * 60000); + this.crowned_chatQuota = new RateLimitChain(10, 2000); require('./Message.js')(this); } isConnected() { @@ -102,4 +108,4 @@ class Client extends EventEmitter { }); } } -module.exports = Client; \ No newline at end of file +module.exports = Client; From 8859255532b4d6b0cdf47cbbd1af39109c3e2b9a Mon Sep 17 00:00:00 2001 From: wolfy01 <45273698+wolfy01@users.noreply.github.com> Date: Tue, 7 Apr 2020 02:04:11 -0400 Subject: [PATCH 010/135] Update Message.js --- src/Message.js | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/src/Message.js b/src/Message.js index b8b79d9..4ed2a24 100644 --- a/src/Message.js +++ b/src/Message.js @@ -30,6 +30,7 @@ module.exports = (cl) => { } }) cl.on("m", msg => { + if (!cl.cursQuota.attempt()) return; if (!(cl.channel && cl.participantId)) return; if (!msg.hasOwnProperty("x")) msg.x = null; if (!msg.hasOwnProperty("y")) msg.y = null; @@ -60,6 +61,15 @@ module.exports = (cl) => { cl.channel.updateCh(); }) cl.on("a", msg => { + if (cl.channel.isLobby(cl.channel._id)) { + if (!cl.chatQuota.attempt()) return; + } else { + if (!(cl.user._id == cl.channel.crown.userId)) { + if (!cl.chatQuota.attempt()) return; + } else { + if (!cl.crowned_chatQuota.attempt()) return; + } + } if (!(cl.channel && cl.participantId)) return; if (!msg.hasOwnProperty('message')) return; if (cl.channel.settings.chat) { @@ -100,6 +110,7 @@ module.exports = (cl) => { cl.server.roomlisteners.delete(cl.connectionid); }) cl.on("userset", msg => { + if (!cl.usersetQuota.attempt()) return; if (!(cl.channel && cl.participantId)) return; if (!msg.hasOwnProperty("set") || !msg.set) msg.set = {}; if (msg.set.hasOwnProperty('name') && typeof msg.set.name == "string") { @@ -165,4 +176,4 @@ module.exports = (cl) => { }) -} \ No newline at end of file +} From 5d9fb96529cc734f4c6d71e99187978611f3560c Mon Sep 17 00:00:00 2001 From: wolfy01 <45273698+wolfy01@users.noreply.github.com> Date: Tue, 7 Apr 2020 02:04:35 -0400 Subject: [PATCH 011/135] Update Client.js --- src/Client.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Client.js b/src/Client.js index 4751df9..4081a1c 100644 --- a/src/Client.js +++ b/src/Client.js @@ -18,7 +18,7 @@ class Client extends EventEmitter { this.bindEventListeners(); this.cursQuota = new RateLimit(16); this.chatQuota = new RateLimitChain(4, 4000); - this.nameQuota = new RateLimitChain(30, 30 * 60000); + this.usersetQuota = new RateLimitChain(30, 30 * 60000); this.crowned_chatQuota = new RateLimitChain(10, 2000); require('./Message.js')(this); } From fe5488c6d81cd7bb371ec168832cf442c5e790e5 Mon Sep 17 00:00:00 2001 From: wolfy01 <45273698+wolfy01@users.noreply.github.com> Date: Tue, 7 Apr 2020 02:16:21 -0400 Subject: [PATCH 012/135] Update Client.js --- src/Client.js | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/src/Client.js b/src/Client.js index 4081a1c..6527005 100644 --- a/src/Client.js +++ b/src/Client.js @@ -16,10 +16,13 @@ class Client extends EventEmitter { this.ip = (req.connection.remoteAddress).replace("::ffff:", ""); this.destroied = false; this.bindEventListeners(); - this.cursQuota = new RateLimit(16); - this.chatQuota = new RateLimitChain(4, 4000); - this.usersetQuota = new RateLimitChain(30, 30 * 60000); - this.crowned_chatQuota = new RateLimitChain(10, 2000); + this.quotas = { + chat: new RateLimitChain(4, 4000), + name: new RateLimitChain(30, 30 * 60000), + cursor: new RateLimit(16), + kickban: new RateLimitChain(2, 1000), + crowned_chat: new RateLimitChain(10, 2000) + } require('./Message.js')(this); } isConnected() { From 7ec508043ab5d41715ad8254028bf7c08a0a3058 Mon Sep 17 00:00:00 2001 From: wolfy01 <45273698+wolfy01@users.noreply.github.com> Date: Tue, 7 Apr 2020 02:17:16 -0400 Subject: [PATCH 013/135] Update Message.js --- src/Message.js | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/src/Message.js b/src/Message.js index 4ed2a24..874b233 100644 --- a/src/Message.js +++ b/src/Message.js @@ -30,7 +30,7 @@ module.exports = (cl) => { } }) cl.on("m", msg => { - if (!cl.cursQuota.attempt()) return; + if (!cl.quotas.cursor.attempt()) return; if (!(cl.channel && cl.participantId)) return; if (!msg.hasOwnProperty("x")) msg.x = null; if (!msg.hasOwnProperty("y")) msg.y = null; @@ -62,12 +62,12 @@ module.exports = (cl) => { }) cl.on("a", msg => { if (cl.channel.isLobby(cl.channel._id)) { - if (!cl.chatQuota.attempt()) return; + if (!cl.quotas.chat.attempt()) return; } else { if (!(cl.user._id == cl.channel.crown.userId)) { - if (!cl.chatQuota.attempt()) return; + if (!cl.quotas.chat.attempt()) return; } else { - if (!cl.crowned_chatQuota.attempt()) return; + if (!cl.quotas.crowned_chat.attempt()) return; } } if (!(cl.channel && cl.participantId)) return; @@ -110,7 +110,7 @@ module.exports = (cl) => { cl.server.roomlisteners.delete(cl.connectionid); }) cl.on("userset", msg => { - if (!cl.usersetQuota.attempt()) return; + if (!cl.quotas.name.attempt()) return; if (!(cl.channel && cl.participantId)) return; if (!msg.hasOwnProperty("set") || !msg.set) msg.set = {}; if (msg.set.hasOwnProperty('name') && typeof msg.set.name == "string") { @@ -132,6 +132,7 @@ module.exports = (cl) => { } }) cl.on('kickban', msg => { + if (!cl.quotas.kickban.attempt()) return; if (!(cl.channel && cl.participantId)) return; if (!(cl.user._id == cl.channel.crown.userId)) return; if (msg.hasOwnProperty('_id') && typeof msg._id == "string") { From 4737f22b946ef33e8b31ae0c56bad90d8323d791 Mon Sep 17 00:00:00 2001 From: wolfy01 <45273698+wolfy01@users.noreply.github.com> Date: Tue, 7 Apr 2020 02:17:29 -0400 Subject: [PATCH 014/135] Delete .gitignore --- .gitignore | 1 - 1 file changed, 1 deletion(-) delete mode 100644 .gitignore diff --git a/.gitignore b/.gitignore deleted file mode 100644 index a6c57f5..0000000 --- a/.gitignore +++ /dev/null @@ -1 +0,0 @@ -*.json From ef612f39fc8fa40ad16baee849bbd0cae39faf30 Mon Sep 17 00:00:00 2001 From: wolfy01 <45273698+wolfy01@users.noreply.github.com> Date: Tue, 7 Apr 2020 02:17:38 -0400 Subject: [PATCH 015/135] Delete .gitattributes --- .gitattributes | 2 -- 1 file changed, 2 deletions(-) delete mode 100644 .gitattributes diff --git a/.gitattributes b/.gitattributes deleted file mode 100644 index dfe0770..0000000 --- a/.gitattributes +++ /dev/null @@ -1,2 +0,0 @@ -# Auto detect text files and perform LF normalization -* text=auto From b1aa913a3004fb5bfb106b7444872b41b17f2b10 Mon Sep 17 00:00:00 2001 From: wolfy01 <45273698+wolfy01@users.noreply.github.com> Date: Tue, 7 Apr 2020 02:18:04 -0400 Subject: [PATCH 016/135] Create users.json --- src/db/users.json | 1 + 1 file changed, 1 insertion(+) create mode 100644 src/db/users.json diff --git a/src/db/users.json b/src/db/users.json new file mode 100644 index 0000000..0967ef4 --- /dev/null +++ b/src/db/users.json @@ -0,0 +1 @@ +{} From 005cada1137a9357506889a9e55215ce1140cd35 Mon Sep 17 00:00:00 2001 From: wolfy01 <45273698+wolfy01@users.noreply.github.com> Date: Tue, 7 Apr 2020 02:18:20 -0400 Subject: [PATCH 017/135] Delete textfile.txt --- src/db/textfile.txt | 0 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100644 src/db/textfile.txt diff --git a/src/db/textfile.txt b/src/db/textfile.txt deleted file mode 100644 index e69de29..0000000 From 34eddd1259182fc05ab6a480666c71ab5fe81d12 Mon Sep 17 00:00:00 2001 From: wolfy01 <45273698+wolfy01@users.noreply.github.com> Date: Tue, 7 Apr 2020 02:19:03 -0400 Subject: [PATCH 018/135] Create config.json --- src/db/config.json | 10 ++++++++++ 1 file changed, 10 insertions(+) create mode 100644 src/db/config.json diff --git a/src/db/config.json b/src/db/config.json new file mode 100644 index 0000000..ce8db5c --- /dev/null +++ b/src/db/config.json @@ -0,0 +1,10 @@ +{ + "port": "3000", + "motd": "You agree to read this message.", + "_id_PrivateKey": "boppity", + "defaultUsername": "Anonymous", + "defaultRoomColor": "#3b5054", + "defaultLobbyColor": "#19b4b9", + "defaultLobbyColor2": "#801014", + "adminpass": "adminpass" +} From 7303d7d7c07b487d536d6efdfcd44e43804d2f50 Mon Sep 17 00:00:00 2001 From: wolfy01 <45273698+wolfy01@users.noreply.github.com> Date: Tue, 7 Apr 2020 02:41:10 -0400 Subject: [PATCH 019/135] Update index.js --- index.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/index.js b/index.js index 62db0b2..81dae58 100644 --- a/index.js +++ b/index.js @@ -15,8 +15,8 @@ global.isObj = function(a){ return typeof a === "object" && !Array.isArray(a) && a !== null; } -let Server = require("./src/Server.js"); -let config = require('./src/db/config.json'); +let Server = require("./src/Server"); +let config = require('./src/db/config'); global.SERVER = new Server(config); let console = process.platform == 'win32' ? new AsyncConsole("", input => { try { From 033f8d3c2aec066a9cf1d07adb406d06fa463708 Mon Sep 17 00:00:00 2001 From: wolfy01 <45273698+wolfy01@users.noreply.github.com> Date: Tue, 7 Apr 2020 02:42:12 -0400 Subject: [PATCH 020/135] quotas --- src/Client.js | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/src/Client.js b/src/Client.js index 6527005..b7f5b54 100644 --- a/src/Client.js +++ b/src/Client.js @@ -1,3 +1,5 @@ +const config = require('./db/config'); +const quotas = config.quotas; const RateLimit = require('./RateLimit.js').RateLimit; const RateLimitChain = require('./RateLimit.js').RateLimitChain; const Room = require("./Room.js"); @@ -17,11 +19,12 @@ class Client extends EventEmitter { this.destroied = false; this.bindEventListeners(); this.quotas = { - chat: new RateLimitChain(4, 4000), - name: new RateLimitChain(30, 30 * 60000), - cursor: new RateLimit(16), - kickban: new RateLimitChain(2, 1000), - crowned_chat: new RateLimitChain(10, 2000) + chat: new RateLimitChain(quotas.chat.amount, quotas.chat.time), + name: new RateLimitChain(quotas.name.amount, quotas.name.time), + room: new RateLimit(quotas.room.time), + cursor: new RateLimit(quotas.cursor.time), + kickban: new RateLimitChain(quotas.kickban.amount, quotas.kickban.time), + crowned_chat: new RateLimitChain(quotas.crowned_chat.amount, quotas.crowned_chat.time) } require('./Message.js')(this); } From fde1745f8293ec7f5918f4fe879a8a5e458caaa2 Mon Sep 17 00:00:00 2001 From: wolfy01 <45273698+wolfy01@users.noreply.github.com> Date: Tue, 7 Apr 2020 02:42:49 -0400 Subject: [PATCH 021/135] room quota --- src/Message.js | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Message.js b/src/Message.js index 874b233..ea4ee86 100644 --- a/src/Message.js +++ b/src/Message.js @@ -23,6 +23,7 @@ module.exports = (cl) => { }]) }) cl.on("ch", msg => { + if (!cl.quotas.room.attempt()) return; if (!msg.hasOwnProperty("set") || !msg.set) msg.set = {}; if (msg.hasOwnProperty("_id") && typeof msg._id == "string") { if (msg._id.length > 512) return; From f6e52ccda05932cc621f4b32f1896439f641028c Mon Sep 17 00:00:00 2001 From: wolfy01 <45273698+wolfy01@users.noreply.github.com> Date: Tue, 7 Apr 2020 02:44:34 -0400 Subject: [PATCH 022/135] Update and rename config.json to config.js Add quotas --- src/db/config.js | 34 ++++++++++++++++++++++++++++++++++ src/db/config.json | 10 ---------- 2 files changed, 34 insertions(+), 10 deletions(-) create mode 100644 src/db/config.js delete mode 100644 src/db/config.json diff --git a/src/db/config.js b/src/db/config.js new file mode 100644 index 0000000..eeeb1e2 --- /dev/null +++ b/src/db/config.js @@ -0,0 +1,34 @@ +module.exports = Object.seal({ + "port": "8080", + "motd": "You agree to read this message.", + "_id_PrivateKey": "boppity", + "defaultUsername": "Anonymous", + "defaultRoomColor": "#3b5054", + "defaultLobbyColor": "#19b4b9", + "defaultLobbyColor2": "#801014", + "adminpass": "adminpass_h4gKJCX2", + "quotas":{ + "chat":{ + "amount": 4, + "time": 4000 + }, + "name":{ + "amount": 30, + "time": 30 * 60000 + }, + "room":{ + "time": 500 + }, + "cursor":{ + "time": 16 + }, + "kickban":{ + "amount": 2, + "time": 1000 + }, + "crowned_chat":{ + "amount": 10, + "time": 4000 + } + } +}) diff --git a/src/db/config.json b/src/db/config.json deleted file mode 100644 index ce8db5c..0000000 --- a/src/db/config.json +++ /dev/null @@ -1,10 +0,0 @@ -{ - "port": "3000", - "motd": "You agree to read this message.", - "_id_PrivateKey": "boppity", - "defaultUsername": "Anonymous", - "defaultRoomColor": "#3b5054", - "defaultLobbyColor": "#19b4b9", - "defaultLobbyColor2": "#801014", - "adminpass": "adminpass" -} From cb7550436539393828b2d9c1a578ec243d632887 Mon Sep 17 00:00:00 2001 From: wolfy01 <45273698+wolfy01@users.noreply.github.com> Date: Tue, 7 Apr 2020 02:45:55 -0400 Subject: [PATCH 023/135] Update config.js --- src/db/config.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/db/config.js b/src/db/config.js index eeeb1e2..58bfddc 100644 --- a/src/db/config.js +++ b/src/db/config.js @@ -1,12 +1,12 @@ module.exports = Object.seal({ - "port": "8080", + "port": "3000", "motd": "You agree to read this message.", "_id_PrivateKey": "boppity", "defaultUsername": "Anonymous", "defaultRoomColor": "#3b5054", "defaultLobbyColor": "#19b4b9", "defaultLobbyColor2": "#801014", - "adminpass": "adminpass_h4gKJCX2", + "adminpass": "adminpass", "quotas":{ "chat":{ "amount": 4, From 4d876c61606b140a252e2faa9717a94d2a6d2548 Mon Sep 17 00:00:00 2001 From: Wolfy Date: Tue, 7 Apr 2020 03:54:17 -0400 Subject: [PATCH 024/135] Remove --- README.md | 2 - index.js | 27 --- package.json | 32 ---- src/Client.js | 117 ------------ src/ColorEncoder.js | 16 -- src/Message.js | 181 ------------------- src/Quota.js | 87 --------- src/Ratelimit.js | 40 ----- src/Room.js | 420 -------------------------------------------- src/Server.js | 41 ----- src/TODO.txt | 2 - src/User.js | 53 ------ src/db/config.js | 34 ---- src/db/users.json | 1 - 14 files changed, 1053 deletions(-) delete mode 100644 README.md delete mode 100644 index.js delete mode 100644 package.json delete mode 100644 src/Client.js delete mode 100644 src/ColorEncoder.js delete mode 100644 src/Message.js delete mode 100644 src/Quota.js delete mode 100644 src/Ratelimit.js delete mode 100644 src/Room.js delete mode 100644 src/Server.js delete mode 100644 src/TODO.txt delete mode 100644 src/User.js delete mode 100644 src/db/config.js delete mode 100644 src/db/users.json diff --git a/README.md b/README.md deleted file mode 100644 index 33b4471..0000000 --- a/README.md +++ /dev/null @@ -1,2 +0,0 @@ -# mpp-server -Attempt at making a MPP Server. \ No newline at end of file diff --git a/index.js b/index.js deleted file mode 100644 index 81dae58..0000000 --- a/index.js +++ /dev/null @@ -1,27 +0,0 @@ -//call new Server -global.WebSocket = require('ws'); -global.EventEmitter = require('events').EventEmitter; -global.fs = require('fs'); -global.createKeccakHash = require('keccak'); -const AsyncConsole = require('asyncconsole') - -global.isString = function(a){ - return typeof a === 'string'; -} -global.isBool = function(a){ - return typeof a === 'boolean'; -} -global.isObj = function(a){ - return typeof a === "object" && !Array.isArray(a) && a !== null; -} - -let Server = require("./src/Server"); -let config = require('./src/db/config'); -global.SERVER = new Server(config); -let console = process.platform == 'win32' ? new AsyncConsole("", input => { - try { - console.log(JSON.stringify(eval(input))); - } catch(e) { - console.log(e.toString()); - } -}) : {}; diff --git a/package.json b/package.json deleted file mode 100644 index 895bc77..0000000 --- a/package.json +++ /dev/null @@ -1,32 +0,0 @@ -{ - "name": "mpp-server-master", - "version": "1.0.0", - "description": "Attempt at making a MPP Server.", - "main": "index.js", - "scripts": { - "test": "echo \"Error: no test specified\" && exit 1" - }, - "repository": { - "type": "git", - "url": "git+https://github.com/BopItFreak/mpp-server.git" - }, - "keywords": [ - "mpp", - "server", - "multiplayerpiano" - ], - "author": "BopItFreak", - "license": "ISC", - "bugs": { - "url": "https://github.com/BopItFreak/mpp-server/issues" - }, - "homepage": "https://github.com/BopItFreak/mpp-server#readme", - "dependencies": { - "asyncconsole": "^1.3.9", - "events": "^3.0.0", - "keccak": "^2.0.0", - "node-json-color-stringify": "^1.1.0", - "ws": "^7.1.2" - }, - "devDependencies": {} -} diff --git a/src/Client.js b/src/Client.js deleted file mode 100644 index b7f5b54..0000000 --- a/src/Client.js +++ /dev/null @@ -1,117 +0,0 @@ -const config = require('./db/config'); -const quotas = config.quotas; -const RateLimit = require('./RateLimit.js').RateLimit; -const RateLimitChain = require('./RateLimit.js').RateLimitChain; -const Room = require("./Room.js"); -require('node-json-color-stringify'); -class Client extends EventEmitter { - constructor(ws, req, server) { - super(); - EventEmitter.call(this); - this.user; - this.connectionid = server.connectionid; - this.server = server; - this.participantId; - this.channel; - this.ws = ws; - this.req = req; - this.ip = (req.connection.remoteAddress).replace("::ffff:", ""); - this.destroied = false; - this.bindEventListeners(); - this.quotas = { - chat: new RateLimitChain(quotas.chat.amount, quotas.chat.time), - name: new RateLimitChain(quotas.name.amount, quotas.name.time), - room: new RateLimit(quotas.room.time), - cursor: new RateLimit(quotas.cursor.time), - kickban: new RateLimitChain(quotas.kickban.amount, quotas.kickban.time), - crowned_chat: new RateLimitChain(quotas.crowned_chat.amount, quotas.crowned_chat.time) - } - require('./Message.js')(this); - } - isConnected() { - return this.ws && this.ws.readyState === WebSocket.OPEN; - } - isConnecting() { - return this.ws && this.ws.readyState === WebSocket.CONNECTING; - } - setChannel(_id, settings) { - if (this.channel && this.channel._id == _id) return; - if (this.server.rooms.get(_id)) { - let room = this.server.rooms.get(_id); - let userbanned = room.bans.get(this.user._id); - if (userbanned && (Date.now() - userbanned.bannedtime >= userbanned.msbanned)) { - room.bans.delete(userbanned.user._id); - userbanned = undefined; - } - if (userbanned) { - console.log(Date.now() - userbanned.bannedtime) - room.Notification(this.user._id, - "Notice", - `Currently banned from \"${_id}\" for ${Math.ceil(Math.floor((userbanned.msbanned - (Date.now() - userbanned.bannedtime)) / 1000) / 60)} minutes.`, - 7000, - "", - "#room", - "short" - ); - return; - } - let channel = this.channel; - if (channel) this.channel.emit("bye", this); - if (channel) this.channel.updateCh(); - this.channel = this.server.rooms.get(_id); - this.channel.join(this); - } else { - let room = new Room(this.server, _id, settings); - this.server.rooms.set(_id, room); - if (this.channel) this.channel.emit("bye", this); - this.channel = this.server.rooms.get(_id); - this.channel.join(this); - } - } - sendArray(arr) { - if (this.isConnected()) { - //console.log(`SEND: `, JSON.colorStringify(arr)); - this.ws.send(JSON.stringify(arr)); - } - } - destroy() { - this.ws.close(); - if (this.channel) { - this.channel.emit("bye", this) - } - this.user; - this.participantId; - this.channel; - this.server.roomlisteners.delete(this.connectionid); - this.connectionid; - this.server.connections.delete(this.connectionid); - this.destroied = true; - console.log(`Removed Connection ${this.connectionid}.`); - } - bindEventListeners() { - this.ws.on("message", (evt, admin) => { - try { - let transmission = JSON.parse(evt); - for (let msg of transmission) { - if (!msg.hasOwnProperty("m")) return; - if (!this.server.legit_m.includes(msg.m)) return; - this.emit(msg.m, msg, !!admin); - //console.log(`RECIEVE: `, JSON.colorStringify(msg)); - } - } catch (e) { - console.log(e) - this.destroy(); - } - }); - this.ws.on("close", () => { - if (!this.destroied) - this.destroy(); - }); - this.ws.addEventListener("error", (err) => { - console.error(err); - if (!this.destroied) - this.destroy(); - }); - } -} -module.exports = Client; diff --git a/src/ColorEncoder.js b/src/ColorEncoder.js deleted file mode 100644 index d91f04b..0000000 --- a/src/ColorEncoder.js +++ /dev/null @@ -1,16 +0,0 @@ -function hashCode(str) { // java String#hashCode - var hash = 0; - for (var i = 0; i < str.length; i++) { - hash = str.charCodeAt(i) + ((hash << 5) - hash); - } - return hash; -} - -function intToRGB(i){ - var c = (i & 0x00FFFFFF) - .toString(16) - .toUpperCase(); - - return "00000".substring(0, 6 - c.length) + c; -} -module.exports = {hashCode, intToRGB}; \ No newline at end of file diff --git a/src/Message.js b/src/Message.js deleted file mode 100644 index ea4ee86..0000000 --- a/src/Message.js +++ /dev/null @@ -1,181 +0,0 @@ -const User = require("./User.js"); -const Room = require("./Room.js"); -module.exports = (cl) => { - cl.once("hi", () => { - let user = new User(cl); - user.getUserData().then((data) => { - let msg = {}; - msg.m = "hi"; - msg.motd = cl.server.welcome_motd; - msg.t = Date.now(); - msg.u = data; - msg.v = "Beta"; - cl.sendArray([msg]) - cl.user = data; - }) - }) - cl.on("t", msg => { - if (msg.hasOwnProperty("e") && !isNaN(msg.e)) - cl.sendArray([{ - m: "t", - t: Date.now(), - e: msg.e - }]) - }) - cl.on("ch", msg => { - if (!cl.quotas.room.attempt()) return; - if (!msg.hasOwnProperty("set") || !msg.set) msg.set = {}; - if (msg.hasOwnProperty("_id") && typeof msg._id == "string") { - if (msg._id.length > 512) return; - cl.setChannel(msg._id, msg.set); - } - }) - cl.on("m", msg => { - if (!cl.quotas.cursor.attempt()) return; - if (!(cl.channel && cl.participantId)) return; - if (!msg.hasOwnProperty("x")) msg.x = null; - if (!msg.hasOwnProperty("y")) msg.y = null; - if (parseInt(msg.x) == NaN) msg.x = null; - if (parseInt(msg.y) == NaN) msg.y = null; - cl.channel.emit("m", cl, msg.x, msg.y) - - }) - cl.on("chown", msg => { - if (!(cl.channel && cl.participantId)) return; - //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 (msg.hasOwnProperty("id")) { - // console.log(cl.channel.crown) - if (cl.user._id == cl.channel.crown.userId || cl.channel.crowndropped) - cl.channel.chown(msg.id); - } else { - if (cl.user._id == cl.channel.crown.userId || cl.channel.crowndropped) - cl.channel.chown(); - } - }) - cl.on("chset", msg => { - if (!(cl.channel && cl.participantId)) return; - if (!(cl.user._id == cl.channel.crown.userId)) return; - if (!msg.hasOwnProperty("set") || !msg.set) msg.set = cl.channel.verifySet(cl.channel._id,{}); - cl.channel.settings = msg.set; - cl.channel.updateCh(); - }) - cl.on("a", msg => { - if (cl.channel.isLobby(cl.channel._id)) { - if (!cl.quotas.chat.attempt()) return; - } else { - if (!(cl.user._id == cl.channel.crown.userId)) { - if (!cl.quotas.chat.attempt()) return; - } else { - if (!cl.quotas.crowned_chat.attempt()) return; - } - } - if (!(cl.channel && cl.participantId)) return; - if (!msg.hasOwnProperty('message')) return; - if (cl.channel.settings.chat) { - cl.channel.emit('a', cl, msg); - } - }) - cl.on('n', msg => { - if (!(cl.channel && cl.participantId)) return; - if (!msg.hasOwnProperty('t') || !msg.hasOwnProperty('n')) return; - if (typeof msg.t != 'number' || typeof msg.n != 'object') return; - if (cl.channel.settings.crownsolo) { - if ((cl.channel.crown.userId == cl.user._id) && !cl.channel.crowndropped) { - cl.channel.playNote(cl, msg); - } - } else { - cl.channel.playNote(cl, msg); - } - }) - cl.on('+ls', msg => { - if (!(cl.channel && cl.participantId)) return; - cl.server.roomlisteners.set(cl.connectionid, cl); - let rooms = []; - for (let room of Array.from(cl.server.rooms.values())) { - let data = room.fetchData().ch; - if (room.bans.get(cl.user._id)) { - data.banned = true; - } - if (room.settings.visible) rooms.push(data); - } - cl.sendArray([{ - "m": "ls", - "c": true, - "u": rooms - }]) - }) - cl.on('-ls', msg => { - if (!(cl.channel && cl.participantId)) return; - cl.server.roomlisteners.delete(cl.connectionid); - }) - cl.on("userset", msg => { - if (!cl.quotas.name.attempt()) return; - 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; - cl.user.name = msg.set.name; - let user = new User(cl); - user.getUserData().then((usr) => { - let dbentry = user.userdb.get(cl.user._id); - if (!dbentry) return; - dbentry.name = msg.set.name; - user.updatedb(); - cl.server.rooms.forEach((room) => { - room.updateParticipant(cl.participantId, { - name: msg.set.name - }); - }) - }) - - } - }) - cl.on('kickban', msg => { - if (!cl.quotas.kickban.attempt()) return; - if (!(cl.channel && cl.participantId)) return; - if (!(cl.user._id == cl.channel.crown.userId)) return; - if (msg.hasOwnProperty('_id') && typeof msg._id == "string") { - let _id = msg._id; - let ms = msg.ms || 0; - cl.channel.kickban(_id, ms); - } - }) - cl.on("bye", msg => { - cl.destroy(); - }) - cl.on("admin message", msg => { - if (!(cl.channel && cl.participantId)) return; - if (!msg.hasOwnProperty('password') || !msg.hasOwnProperty('msg')) return; - if (typeof msg.msg != 'object') return; - if (msg.password !== cl.server.adminpass) return; - cl.ws.emit("message", JSON.stringify([msg.msg]), true); - }) - //admin only stuff - cl.on('color', (msg, admin) => { - if (!admin) return; - if (typeof cl.channel.verifyColor(msg.color) != 'string') return; - if (!msg.hasOwnProperty('id') && !msg.hasOwnProperty('_id')) return; - cl.server.connections.forEach((usr) => { - if ((usr.channel && usr.participantId && usr.user) && (usr.user._id == msg._id || (usr.participantId == msg.id))) { - let user = new User(usr); - user.cl.user.color = msg.color; - user.getUserData().then((uSr) => { - if (!uSr._id) return; - let dbentry = user.userdb.get(uSr._id); - if (!dbentry) return; - dbentry.color = msg.color; - //user.updatedb(); - cl.server.rooms.forEach((room) => { - room.updateParticipant(usr.participantId, { - color: msg.color - }); - }) - }) - } - }) - - }) - -} diff --git a/src/Quota.js b/src/Quota.js deleted file mode 100644 index 16bb717..0000000 --- a/src/Quota.js +++ /dev/null @@ -1,87 +0,0 @@ -class Quota { - constructor(cb) { - this.cb = cb; - this.setParams(); - this.resetPoints(); - }; - static NQ_PARAMS_LOBBY = { - allowance: 200, - max: 600 - }; - static NQ_PARAMS_NORMAL = { - allowance: 400, - max: 1200 - }; - static NQ_PARAMS_RIDICULOUS = { - allowance: 600, - max: 1800 - }; - static NQ_PARAMS_OFFLINE = { - allowance: 8000, - max: 24000, - maxHistLen: 3 - }; - static CH_PARAMS = { - allowance: 8000, - max: 24000, - maxHistLen: 3 - } - getParams() { - return { - m: "nq", - allowance: this.allowance, - max: this.max, - maxHistLen: this.maxHistLen - }; - }; - setParams(params) { - params = params || NoteQuota.PARAMS_OFFLINE; - var allowance = params.allowance || this.allowance || NoteQuota.PARAMS_OFFLINE.allowance; - var max = params.max || this.max || NoteQuota.PARAMS_OFFLINE.max; - var maxHistLen = params.maxHistLen || this.maxHistLen || NoteQuota.PARAMS_OFFLINE.maxHistLen; - if (allowance !== this.allowance || max !== this.max || maxHistLen !== this.maxHistLen) { - this.allowance = allowance; - this.max = max; - this.maxHistLen = maxHistLen; - this.resetPoints(); - return true; - } - return false; - }; - resetPoints() { - this.points = this.max; - this.history = []; - for (var i = 0; i < this.maxHistLen; i++) - this.history.unshift(this.points); - if (this.cb) this.cb(this.points); - }; - tick() { - // keep a brief history - this.history.unshift(this.points); - this.history.length = this.maxHistLen; - // hook a brother up with some more quota - if (this.points < this.max) { - this.points += this.allowance; - if (this.points > this.max) this.points = this.max; - // fire callback - if (this.cb) this.cb(this.points); - } - }; - spend(needed) { - // check whether aggressive limitation is needed - var sum = 0; - for (var i in this.history) { - sum += this.history[i]; - } - if (sum <= 0) needed *= this.allowance; - // can they afford it? spend - if (this.points < needed) { - return false; - } else { - this.points -= needed; - if (this.cb) this.cb(this.points); // fire callback - return true; - } - }; -} -module.exports = Quota; \ No newline at end of file diff --git a/src/Ratelimit.js b/src/Ratelimit.js deleted file mode 100644 index f43157d..0000000 --- a/src/Ratelimit.js +++ /dev/null @@ -1,40 +0,0 @@ - -var RateLimit = function(interval_ms) { - this._interval_ms = interval_ms || 0; // (0 means no limit) - this._after = 0; -}; - -RateLimit.prototype.attempt = function(time) { - var time = time || Date.now(); - if(time < this._after) return false; - this._after = time + this._interval_ms; - return true; -}; - -RateLimit.prototype.setInterval = function(interval_ms) { - this._after += interval_ms - this._interval_ms; - this._interval_ms = interval_ms; -}; - -var RateLimitChain = function(num, interval_ms) { - this.setNumAndInterval(num, interval_ms); -}; - -RateLimitChain.prototype.attempt = function(time) { - var time = time || Date.now(); - for(var i = 0; i < this._chain.length; i++) { - if(this._chain[i].attempt(time)) return true; - } - return false; -}; - -RateLimitChain.prototype.setNumAndInterval = function(num, interval_ms) { - this._chain = []; - for(var i = 0; i < num; i++) { - this._chain.push(new RateLimit(interval_ms)); - } -}; - -var exports = typeof module !== "undefined" ? module.exports : this; -exports.RateLimit = RateLimit; -exports.RateLimitChain = RateLimitChain; diff --git a/src/Room.js b/src/Room.js deleted file mode 100644 index f6f6520..0000000 --- a/src/Room.js +++ /dev/null @@ -1,420 +0,0 @@ -//array of rooms -//room class -//room deleter -//databases in Map - -class Room extends EventEmitter { - constructor(server, _id, settings) { - super(); - EventEmitter.call(this); - this._id = _id; - this.server = server; - this.crown = null; - this.crowndropped = false; - this.settings = this.verifySet(this._id,{set:settings}); - this.chatmsgs = []; - this.ppl = new Map(); - this.connections = []; - this.bindEventListeners(); - this.server.rooms.set(_id, this); - this.bans = new Map(); - } - join(cl) { //this stuff is complicated - let otheruser = this.connections.find((a) => a.user._id == cl.user._id) - if (!otheruser) { - let participantId = createKeccakHash('keccak256').update((Math.random().toString() + cl.ip)).digest('hex').substr(0, 24); - cl.user.id = participantId; - cl.participantId = participantId; - if (((this.connections.length == 0 && Array.from(this.ppl.values()).length == 0) && !this.isLobby(this._id)) || this.crown && (this.crown.userId == cl.user._id)) { //user that created the room, give them the crown. - this.crown = { - participantId: cl.participantId, - userId: cl.user._id, - time: Date.now(), - startPos: { - x: 50, - y: 50 - }, - endPos: { - x: this.getCrownX(), - y: this.getCrownY() - } - } - this.crowndropped = false; - } - this.ppl.set(participantId, cl); - this.connections.push(cl); - 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, - 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) - }]) - this.updateCh(cl); - } else { - cl.user.id = otheruser.participantId; - cl.participantId = otheruser.participantId; - this.connections.push(cl); - cl.sendArray([{ - m: "c", - c: this.chatmsgs.slice(-1 * 32) - }]) - this.updateCh(cl); - } - - } - remove(p) { //this is complicated too - let otheruser = this.connections.filter((a) => a.user._id == p.user._id); - if (!(otheruser.length > 1)) { - this.ppl.delete(p.participantId); - this.connections.splice(this.connections.findIndex((a) => a.connectionid == p.connectionid), 1); - console.log(`Deleted client ${p.user.id}`); - this.sendArray([{ - m: "bye", - p: p.participantId - }], p, false); - if (this.crown) - if (this.crown.userId == p.user._id && !this.crowndropped) { - this.chown(); - } - this.updateCh(); - } else { - this.connections.splice(this.connections.findIndex((a) => a.connectionid == p.connectionid), 1); - } - - } - updateCh(cl) { //update channel for all people in channel - if (Array.from(this.ppl.values()).length <= 0) this.destroy(); - this.connections.forEach((usr) => { - this.server.connections.get(usr.connectionid).sendArray([this.fetchData(usr, cl)]) - }) - this.server.updateRoom(this.fetchData()); - } - updateParticipant(pid, options) { - let p = this.ppl.get(pid); - if (!p) return; - options.name ? this.ppl.get(pid).user.name = options.name : {}; - options._id ? this.ppl.get(pid).user._id = options._id : {}; - options.color ? this.ppl.get(pid).user.color = options.color : {}; - this.connections.filter((ofo) => ofo.participantId == p.participantId).forEach((usr) => { - options.name ? usr.user.name = options.name : {}; - options._id ? usr.user._id = options._id : {}; - options.color ? usr.user.color = options.color : {}; - }) - this.sendArray([{ - color: p.user.color, - id: p.participantId, - m: "p", - name: p.user.name, - x: p.x || 200, - y: p.y || 100, - _id: p.user._id - }]) - } - destroy() { //destroy room - this._id; - console.log(`Deleted room ${this._id}`); - this.settings = {}; - this.ppl; - this.connnections; - this.chatmsgs; - this.server.rooms.delete(this._id); - } - sendArray(arr, not, onlythisparticipant) { - this.connections.forEach((usr) => { - if (!not || (usr.participantId != not.participantId && !onlythisparticipant) || (usr.connectionid != not.connectionid && onlythisparticipant)) { - try { - this.server.connections.get(usr.connectionid).sendArray(arr) - } catch (e) { - console.log(e); - } - } - }) - } - fetchData(usr, cl) { - let chppl = []; - [...this.ppl.values()].forEach((a) => { - chppl.push(a.user); - }) - let data = { - m: "ch", - p: "ofo", - ch: { - count: chppl.length, - crown: this.crown, - settings: this.settings, - _id: this._id - }, - ppl: chppl - } - if (cl) { - if (usr.connectionid == cl.connectionid) { - data.p = cl.participantId; - } else { - delete data.p; - } - } else { - delete data.p; - } - if (data.ch.crown == null) { - delete data.ch.crown; - } else { - - } - return data; - } - verifyColor(strColor){ - var test2 = /^#[0-9A-F]{6}$/i.test(strColor); - if(test2 == true){ - return strColor; - } else{ - return false; - } - } - isLobby(_id) { - if (_id.startsWith("lobby")) { - let lobbynum = _id.split("lobby")[1]; - if (_id == "lobby") { - return true; - } - if (!(parseInt(lobbynum).toString() == lobbynum)) return false; - for (let i in lobbynum) { - if (parseInt(lobbynum[i]) >= 0) { - if (parseInt(i) + 1 == lobbynum.length) return true; - - } else { - return false; - } - } - } else if (_id.startsWith("test/")) { - if (_id == "test/") { - return false; - } else { - return true; - } - } else { - return false; - } - - } - getCrownY() { - return 50 - 30; - } - getCrownX() { - return 50; - } - chown(id) { - let prsn = this.ppl.get(id); - if (prsn) { - this.crown = { - participantId: prsn.participantId, - userId: prsn.user._id, - time: Date.now(), - startPos: { - x: 50, - y: 50 - }, - endPos: { - x: this.getCrownX(), - y: this.getCrownY() - }, - } - this.crowndropped = false; - } else { - this.crown = { - userId: this.crown.userId, - time: Date.now(), - startPos: { - x: 50, - y: 50 - }, - endPos: { - x: this.getCrownX(), - y: this.getCrownY() - } - } - this.crowndropped = true; - } - this.updateCh(); - } - setCords(p, x, y) { - if (p.participantId && this.ppl.get(p.participantId)) { - x ? this.ppl.get(p.participantId).x = x : {}; - y ? this.ppl.get(p.participantId).y = y : {}; - this.sendArray([{ - m: "m", - id: p.participantId, - x: this.ppl.get(p.participantId).x, - y: this.ppl.get(p.participantId).y - }], p, false); - } - } - chat(p, msg) { - if (msg.message.length > 512) return; - let filter = ["AMIGHTYWIND"]; - let regexp = new RegExp("\\b(" + filter.join("|") + ")\\b", "i"); - if (regexp.test(msg.message)) return; - let prsn = this.ppl.get(p.participantId); - if (prsn) { - let message = {}; - message.m = "a"; - message.a = msg.message; - message.p = { - color: p.user.color, - id: p.participantId, - name: p.user.name, - _id: p.user._id - }; - message.t = Date.now(); - this.sendArray([message]); - this.chatmsgs.push(message); - } - } - playNote(cl, note) { - this.sendArray([{ - m: "n", - n: note.n, - p: cl.participantId, - t: note.t - }], cl, true); - } - kickban(_id, ms) { - ms = parseInt(ms); - if (ms >= (1000 * 60 * 60 - 500)) return; - if (ms < 0) return; - ms = Math.round(ms / 1000) * 1000; - let user = this.connections.find((usr) => usr.user._id == _id); - if (!user) return; - let asd = true; - let tonc = true; - let pthatbanned = this.ppl.get(this.crown.participantId); - this.connections.filter((usr) => usr.participantId == user.participantId).forEach((u) => { - user.bantime = Math.floor(Math.floor(ms / 1000) / 60); - user.bannedtime = Date.now(); - user.msbanned = ms; - this.bans.set(user.user._id, user); - if (this.crown && (this.crown.userId)) { - u.setChannel("test/awkward", {}); - if (asd) - this.Notification(user.user._id, - "Notice", - `Banned from \"${this._id}\" for ${Math.floor(Math.floor(ms / 1000) / 60)} minutes.`, - "", - 7000, - "#room", - "short" - ) - if (asd) - this.Notification("room", - "Notice", - `${pthatbanned.user.name} banned ${user.user.name} from the channel for ${Math.floor(Math.floor(ms / 1000) / 60)} minutes.`, - "", - 7000, - "#room", - "short" - ) - if (this.crown && (this.crown.userId == _id) && tonc) { - this.Notification("room", - "Certificate of Award", - `Let it be known that ${user.user.name} kickbanned him/her self.`, - "", - 7000, - "#room" - ); - tonc = false; - } - - } - - }) - } - Notification(who, title, text, html, duration, target, klass, id) { - let obj = { - m: "notification", - title: title, - text: text, - html: html, - target: target, - duration: duration, - class: klass, - id: id - }; - if (!id) delete obj.id; - if (!title) delete obj.title; - if (!text) delete obj.text; - if (!html) delete obj.html; - if (!target) delete obj.target; - if (!duration) delete obj.duration; - if (!klass) delete obj.class; - switch (who) { - case "all": { - for (let con of Array.from(this.server.connections.values())) { - con.sendArray([obj]); - } - break; - } - case "room": { - for (let con of this.connections) { - con.sendArray([obj]); - } - break; - } - default: { - Array.from(this.server.connections.values()).filter((usr) => usr.user._id == who).forEach((p) => { - p.sendArray([obj]); - }); - } - } - } - bindEventListeners() { - this.on("bye", participant => { - this.remove(participant); - }) - - this.on("m", (participant, x, y) => { - this.setCords(participant, x, y); - }) - - this.on("a", (participant, msg) => { - this.chat(participant, msg); - }) - } - verifySet(_id,msg){ - if(!isObj(msg.set)) msg.set = {visible:true,color:this.server.defaultRoomColor,chat:true,crownsolo:false}; - if(isBool(msg.set.lobby)){ - if(!this.isLobby(_id)) delete msg.set.lobby; // keep it nice and clean - }else{ - if(this.isLobby(_id)) msg.set = {visible:true,color:this.server.defaultLobbyColor,color2:this.server.defaultLobbyColor2,chat:true,crownsolo:false,lobby:true}; - } - if(!isBool(msg.set.visible)){ - if(msg.set.visible == undefined) msg.set.visible = (!isObj(this.settings) ? true : this.settings.visible); - else msg.set.visible = true; - }; - if(!isBool(msg.set.chat)){ - if(msg.set.chat == undefined) msg.set.chat = (!isObj(this.settings) ? true : this.settings.chat); - else msg.set.chat = true; - }; - if(!isBool(msg.set.crownsolo)){ - if(msg.set.crownsolo == undefined) msg.set.crownsolo = (!isObj(this.settings) ? false : this.settings.crownsolo); - else msg.set.crownsolo = false; - }; - if(!isString(msg.set.color) || !/^#[0-9a-f]{6}$/i.test(msg.set.color)) msg.set.color = (!isObj(this.settings) ? this.server.defaultRoomColor : this.settings.color); - if(isString(msg.set.color2)){ - if(!/^#[0-9a-f]{6}$/i.test(msg.set.color2)){ - if(this.settings){ - if(this.settings.color2) msg.set.color2 = this.settings.color2; - else delete msg.set.color2; // keep it nice and clean - } - } - }; - return msg.set; - } - -} -module.exports = Room; diff --git a/src/Server.js b/src/Server.js deleted file mode 100644 index 8d29a44..0000000 --- a/src/Server.js +++ /dev/null @@ -1,41 +0,0 @@ -const Client = require("./Client.js") -class Server extends EventEmitter { - constructor(config) { - super(); - EventEmitter.call(this); - this.wss = new WebSocket.Server({ - port: config.port, - backlog: 100, - verifyClient: function (info, done) { - done(true) - } - }); - this.connectionid = 0; - this.connections = new Map(); - this.roomlisteners = new Map(); - this.rooms = new Map(); - this.wss.on('connection', (ws, req) => { - this.connections.set(++this.connectionid, new Client(ws, req, this)); - }); - this.legit_m = ["a", "bye", "hi", "ch", "+ls", "-ls", "m", "n", "devices", "t", "chset", "userset", "chown", "kickban", "admin message", "color"] - this.welcome_motd = config.motd || "You agree to read this message."; - this._id_Private_Key = config._id_PrivateKey || "boppity"; - this.defaultUsername = config.defaultUsername || "Anonymous"; - this.defaultRoomColor = config.defaultRoomColor || "#3b5054"; - this.defaultLobbyColor = config.defaultLobbyColor || "#19b4b9"; - this.defaultLobbyColor2 = config.defaultLobbyColor2 || "#801014"; - this.adminpass = config.adminpass || "Bop It"; - }; - updateRoom(data) { - if (!data.ch.settings.visible) return; - for (let cl of Array.from(this.roomlisteners.values())) { - cl.sendArray([{ - "m": "ls", - "c": false, - "u": [data.ch] - }]) - } - } -} - -module.exports = Server; \ No newline at end of file diff --git a/src/TODO.txt b/src/TODO.txt deleted file mode 100644 index f9af52b..0000000 --- a/src/TODO.txt +++ /dev/null @@ -1,2 +0,0 @@ - -Room.js make color verifier diff --git a/src/User.js b/src/User.js deleted file mode 100644 index bd10b83..0000000 --- a/src/User.js +++ /dev/null @@ -1,53 +0,0 @@ -const ColorEncoder = require("./ColorEncoder.js"); -const { promisify } = require('util'); -let userdb; -class User { - constructor(cl) { - this.cl = cl; - this.server = this.cl.server; - this.userdb = userdb; - this.default_db = {}; - } - async getUserData() { - if (!userdb || (userdb instanceof Map && [...userdb.entries()] == [])) { - await this.setUpDb(); - } - let _id = createKeccakHash('keccak256').update((this.cl.server._id_Private_Key + this.cl.ip)).digest('hex').substr(0, 24); - let usertofind = userdb.get(_id); - if (!usertofind) { - if (typeof usertofind == 'object' && (usertofind.hasOwnProperty('name') && usertofind.name != this.server.defaultUsername)) return; - userdb.set(_id, { - "color": `#${ColorEncoder.intToRGB(ColorEncoder.hashCode(_id)).toLowerCase()}`, - "name": this.server.defaultUsername, - "_id": _id, - "ip": this.cl.ip - }); - this.updatedb(); - } - let user = userdb.get(_id); - return { - "color": user.color, - "name": user.name, - "_id": user._id, - } - } - async updatedb() { - const writeFile = promisify(fs.writeFile); - await writeFile('src/db/users.json', JSON.stringify(User.strMapToObj(userdb), null, 2)); - } - async setUpDb() { - const writeFile = promisify(fs.writeFile); - const readdir = promisify(fs.readdir); - let files = await readdir("src/db/"); - if (!files.includes("users.json")) { - await writeFile('src/db/users.json', JSON.stringify(this.default_db, null, 2)) - userdb = new Map(Object.entries(require("./db/users.json"))); - } else { - userdb = new Map(Object.entries(require("./db/users.json"))); - } - } - static strMapToObj(strMap) { - return [...strMap.entries()].reduce((obj, [key, value]) => (obj[key] = value, obj), {}); - } -} -module.exports = User; \ No newline at end of file diff --git a/src/db/config.js b/src/db/config.js deleted file mode 100644 index 58bfddc..0000000 --- a/src/db/config.js +++ /dev/null @@ -1,34 +0,0 @@ -module.exports = Object.seal({ - "port": "3000", - "motd": "You agree to read this message.", - "_id_PrivateKey": "boppity", - "defaultUsername": "Anonymous", - "defaultRoomColor": "#3b5054", - "defaultLobbyColor": "#19b4b9", - "defaultLobbyColor2": "#801014", - "adminpass": "adminpass", - "quotas":{ - "chat":{ - "amount": 4, - "time": 4000 - }, - "name":{ - "amount": 30, - "time": 30 * 60000 - }, - "room":{ - "time": 500 - }, - "cursor":{ - "time": 16 - }, - "kickban":{ - "amount": 2, - "time": 1000 - }, - "crowned_chat":{ - "amount": 10, - "time": 4000 - } - } -}) diff --git a/src/db/users.json b/src/db/users.json deleted file mode 100644 index 0967ef4..0000000 --- a/src/db/users.json +++ /dev/null @@ -1 +0,0 @@ -{} From b6c3828629d8b92dbff114a332e242dc3b454918 Mon Sep 17 00:00:00 2001 From: Wolfy Date: Tue, 7 Apr 2020 03:55:16 -0400 Subject: [PATCH 025/135] Add Add everything --- Quotas.js | 51 ++++++ README.md | 2 + banned.json | 3 + config.js | 10 + index.js | 27 +++ package.json | 32 ++++ src/Client.js | 121 +++++++++++++ src/ColorEncoder.js | 16 ++ src/Message.js | 254 ++++++++++++++++++++++++++ src/Quota.js | 58 ++++++ src/Ratelimit.js | 40 ++++ src/Room.js | 432 ++++++++++++++++++++++++++++++++++++++++++++ src/Server.js | 45 +++++ src/TODO.txt | 2 + src/User.js | 56 ++++++ src/db/users.json | 114 ++++++++++++ 16 files changed, 1263 insertions(+) create mode 100644 Quotas.js create mode 100644 README.md create mode 100644 banned.json create mode 100644 config.js create mode 100644 index.js create mode 100644 package.json create mode 100644 src/Client.js create mode 100644 src/ColorEncoder.js create mode 100644 src/Message.js create mode 100644 src/Quota.js create mode 100644 src/Ratelimit.js create mode 100644 src/Room.js create mode 100644 src/Server.js create mode 100644 src/TODO.txt create mode 100644 src/User.js create mode 100644 src/db/users.json diff --git a/Quotas.js b/Quotas.js new file mode 100644 index 0000000..8953448 --- /dev/null +++ b/Quotas.js @@ -0,0 +1,51 @@ +module.exports = Object.seal({ + "note": { + "lobby": { + "allowance": 200, + "max": 600, + "maxHistLen": 3 + }, + "normal": { + "allowance": 400, + "max": 1200, + "maxHistLen": 3 + }, + "insane": { + "allowance": 600, + "max": 1800, + "maxHistLen": 3 + } + }, + "chat": { + "lobby": { + "amount": 4, + "time": 4000 + }, + "normal": { + "amount": 4, + "time": 4000 + }, + "insane": { + "amount": 10, + "time": 4000 + } + }, + "chown": { + "amount": 10, + "time": 5000 + }, + "name": { + "amount": 30, + "time": 30 * 60000 + }, + "room": { + "time": 500 + }, + "cursor": { + "time": 16 + }, + "kickban": { + "amount": 2, + "time": 1000 + } +}) \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..33b4471 --- /dev/null +++ b/README.md @@ -0,0 +1,2 @@ +# mpp-server +Attempt at making a MPP Server. \ No newline at end of file diff --git a/banned.json b/banned.json new file mode 100644 index 0000000..1610ea1 --- /dev/null +++ b/banned.json @@ -0,0 +1,3 @@ +[ + +] \ No newline at end of file diff --git a/config.js b/config.js new file mode 100644 index 0000000..e27916c --- /dev/null +++ b/config.js @@ -0,0 +1,10 @@ +module.exports = Object.seal({ + "port": "8080", + "motd": "You agree to read this message.", + "_id_PrivateKey": "boppity", + "defaultUsername": "Anonymous", + "defaultRoomColor": "#3b5054", + "defaultLobbyColor": "#19b4b9", + "defaultLobbyColor2": "#801014", + "adminpass": "27PP6YLTxg0b1P2B8eGSOki1" +}) \ No newline at end of file diff --git a/index.js b/index.js new file mode 100644 index 0000000..8442191 --- /dev/null +++ b/index.js @@ -0,0 +1,27 @@ +//call new Server +global.WebSocket = require('ws'); +global.EventEmitter = require('events').EventEmitter; +global.fs = require('fs'); +global.createKeccakHash = require('keccak'); +const AsyncConsole = require('asyncconsole') + +global.isString = function(a){ + return typeof a === 'string'; +} +global.isBool = function(a){ + return typeof a === 'boolean'; +} +global.isObj = function(a){ + return typeof a === "object" && !Array.isArray(a) && a !== null; +} + +let Server = require("./src/Server"); +let config = require('./config'); +global.SERVER = new Server(config); +let console = process.platform == 'win32' ? new AsyncConsole("", input => { + try { + console.log(JSON.stringify(eval(input))); + } catch(e) { + console.log(e.toString()); + } +}) : {}; diff --git a/package.json b/package.json new file mode 100644 index 0000000..85f2681 --- /dev/null +++ b/package.json @@ -0,0 +1,32 @@ +{ + "name": "mpp-server-master", + "version": "1.0.0", + "description": "Attempt at making a MPP Server.", + "main": "index.js", + "scripts": { + "test": "echo \"Error: no test specified\" && exit 1" + }, + "repository": { + "type": "git", + "url": "git+https://github.com/BopItFreak/mpp-server.git" + }, + "keywords": [ + "mpp", + "server", + "multiplayerpiano" + ], + "author": "BopItFreak", + "license": "ISC", + "bugs": { + "url": "https://github.com/BopItFreak/mpp-server/issues" + }, + "homepage": "https://github.com/BopItFreak/mpp-server#readme", + "dependencies": { + "asyncconsole": "^1.3.9", + "events": "^3.1.0", + "keccak": "^2.1.0", + "node-json-color-stringify": "^1.1.0", + "ws": "^7.2.3" + }, + "devDependencies": {} +} diff --git a/src/Client.js b/src/Client.js new file mode 100644 index 0000000..d3c4f32 --- /dev/null +++ b/src/Client.js @@ -0,0 +1,121 @@ +const quotas = require('../Quotas'); +const RateLimit = require('./RateLimit.js').RateLimit; +const RateLimitChain = require('./RateLimit.js').RateLimitChain; +const Room = require("./Room.js"); +require('node-json-color-stringify'); +class Client extends EventEmitter { + constructor(ws, req, server) { + super(); + EventEmitter.call(this); + this.user; + this.connectionid = server.connectionid; + this.server = server; + this.participantId; + this.channel; + this.ws = ws; + this.req = req; + this.ip = (req.connection.remoteAddress).replace("::ffff:", ""); + this.destroied = false; + this.bindEventListeners(); + this.quotas = { + //note: new limiter(2000, { allowance:3000, max:24000, maxHistLen:3}), + chat: { + lobby: new RateLimitChain(quotas.chat.lobby.amount, quotas.chat.lobby.time), + normal: new RateLimitChain(quotas.chat.normal.amount, quotas.chat.normal.time), + insane: new RateLimitChain(quotas.chat.insane.amount, quotas.chat.insane.time) + }, + name: new RateLimitChain(quotas.name.amount, quotas.name.time), + room: new RateLimit(quotas.room.time), + chown: new RateLimitChain(quotas.chown.amount, quotas.chown.time), + cursor: new RateLimit(quotas.cursor.time), + kickban: new RateLimitChain(quotas.kickban.amount, quotas.kickban.time), + } + require('./Message.js')(this); + } + isConnected() { + return this.ws && this.ws.readyState === WebSocket.OPEN; + } + isConnecting() { + return this.ws && this.ws.readyState === WebSocket.CONNECTING; + } + setChannel(_id, settings) { + if (this.channel && this.channel._id == _id) return; + if (this.server.rooms.get(_id)) { + let room = this.server.rooms.get(_id); + let userbanned = room.bans.get(this.user._id); + if (userbanned && (Date.now() - userbanned.bannedtime >= userbanned.msbanned)) { + room.bans.delete(userbanned.user._id); + userbanned = undefined; + } + if (userbanned) { + console.log(Date.now() - userbanned.bannedtime) + room.Notification(this.user._id, + "Notice", + `Currently banned from \"${_id}\" for ${Math.ceil(Math.floor((userbanned.msbanned - (Date.now() - userbanned.bannedtime)) / 1000) / 60)} minutes.`, + 7000, + "", + "#room", + "short" + ); + return; + } + let channel = this.channel; + if (channel) this.channel.emit("bye", this); + if (channel) this.channel.updateCh(); + this.channel = this.server.rooms.get(_id); + this.channel.join(this); + } else { + let room = new Room(this.server, _id, settings); + this.server.rooms.set(_id, room); + if (this.channel) this.channel.emit("bye", this); + this.channel = this.server.rooms.get(_id); + this.channel.join(this); + } + } + sendArray(arr) { + if (this.isConnected()) { + //console.log(`SEND: `, JSON.colorStringify(arr)); + this.ws.send(JSON.stringify(arr)); + } + } + destroy() { + this.ws.close(); + if (this.channel) { + this.channel.emit("bye", this) + } + this.user; + this.participantId; + this.channel; + this.server.roomlisteners.delete(this.connectionid); + this.connectionid; + this.server.connections.delete(this.connectionid); + this.destroied = true; + console.log(`Removed Connection ${this.connectionid}.`); + } + bindEventListeners() { + this.ws.on("message", (evt, admin) => { + try { + let transmission = JSON.parse(evt); + for (let msg of transmission) { + if (!msg.hasOwnProperty("m")) return; + if (!this.server.legit_m.includes(msg.m)) return; + this.emit(msg.m, msg, !!admin); + //console.log(`RECIEVE: `, JSON.colorStringify(msg)); + } + } catch (e) { + console.log(e) + this.destroy(); + } + }); + this.ws.on("close", () => { + if (!this.destroied) + this.destroy(); + }); + this.ws.addEventListener("error", (err) => { + console.error(err); + if (!this.destroied) + this.destroy(); + }); + } +} +module.exports = Client; \ No newline at end of file diff --git a/src/ColorEncoder.js b/src/ColorEncoder.js new file mode 100644 index 0000000..d91f04b --- /dev/null +++ b/src/ColorEncoder.js @@ -0,0 +1,16 @@ +function hashCode(str) { // java String#hashCode + var hash = 0; + for (var i = 0; i < str.length; i++) { + hash = str.charCodeAt(i) + ((hash << 5) - hash); + } + return hash; +} + +function intToRGB(i){ + var c = (i & 0x00FFFFFF) + .toString(16) + .toUpperCase(); + + return "00000".substring(0, 6 - c.length) + c; +} +module.exports = {hashCode, intToRGB}; \ No newline at end of file diff --git a/src/Message.js b/src/Message.js new file mode 100644 index 0000000..c62d304 --- /dev/null +++ b/src/Message.js @@ -0,0 +1,254 @@ +const config = require('./db/config'); +const quotas = config.quotas; +const User = require("./User.js"); +module.exports = (cl) => { + cl.once("hi", () => { + let user = new User(cl); + user.getUserData().then((data) => { + let msg = {}; + msg.m = "hi"; + msg.motd = cl.server.welcome_motd; + msg.t = Date.now(); + msg.u = data; + msg.v = "Beta"; + cl.sendArray([msg]) + cl.user = data; + }) + }) + cl.on("t", msg => { + if (msg.hasOwnProperty("e") && !isNaN(msg.e)) + cl.sendArray([{ + m: "t", + t: Date.now(), + e: msg.e + }]) + }) + cl.on("ch", msg => { + if (!cl.quotas.room.attempt()) return; + if (!msg.hasOwnProperty("set") || !msg.set) msg.set = {}; + if (msg.hasOwnProperty("_id") && typeof msg._id == "string") { + if (msg._id.length > 512) return; + cl.setChannel(msg._id, msg.set); + if (cl.channel.isLobby(cl.channel._id)) { + cl.channel.sendNotequota(quotas.note.lobby.allowance, quotas.note.lobby.max, quotas.note.lobby.maxHistLen); + } else { + if (!(cl.user._id == cl.channel.crown.userId)) { + cl.channel.sendNotequota(quotas.note.normal.allowance, quotas.note.normal.max, quotas.note.normal.maxHistLen); + } else { + cl.channel.sendNotequota(quotas.note.insane.allowance, quotas.note.insane.max, quotas.note.insane.maxHistLen); + } + } + } + }) + cl.on("m", msg => { + if (!cl.quotas.cursor.attempt()) return; + if (!(cl.channel && cl.participantId)) return; + if (!msg.hasOwnProperty("x")) msg.x = null; + if (!msg.hasOwnProperty("y")) msg.y = null; + if (parseInt(msg.x) == NaN) msg.x = null; + if (parseInt(msg.y) == NaN) msg.y = null; + cl.channel.emit("m", cl, msg.x, msg.y) + + }) + cl.on("chown", msg => { + if (!cl.quotas.chown.attempt()) return; + if (!(cl.channel && cl.participantId)) return; + //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 (msg.hasOwnProperty("id")) { + // console.log(cl.channel.crown) + if (cl.user._id == cl.channel.crown.userId || cl.channel.crowndropped) + cl.channel.chown(msg.id); + } else { + if (cl.user._id == cl.channel.crown.userId || cl.channel.crowndropped) + cl.channel.chown(); + } + }) + cl.on("chset", msg => { + if (!(cl.channel && cl.participantId)) return; + if (!(cl.user._id == cl.channel.crown.userId)) return; + if (!msg.hasOwnProperty("set") || !msg.set) msg.set = cl.channel.verifySet(cl.channel._id,{}); + cl.channel.settings = msg.set; + cl.channel.updateCh(); + }) + cl.on("a", msg => { + if (cl.channel.isLobby(cl.channel._id)) { + if (!cl.quotas.chat.lobby.attempt()) return; + } else { + if (!(cl.user._id == cl.channel.crown.userId)) { + if (!cl.quotas.chat.normal.attempt()) return; + } else { + if (!cl.quotas.chat.insane.attempt()) return; + } + } + if (!(cl.channel && cl.participantId)) return; + if (!msg.hasOwnProperty('message')) return; + if (cl.channel.settings.chat) { + cl.channel.emit('a', cl, msg); + } + }) + cl.on('n', msg => { + if (!(cl.channel && cl.participantId)) return; + if (!msg.hasOwnProperty('t') || !msg.hasOwnProperty('n')) return; + if (typeof msg.t != 'number' || typeof msg.n != 'object') return; + if (cl.channel.settings.crownsolo) { + if ((cl.channel.crown.userId == cl.user._id) && !cl.channel.crowndropped) { + cl.channel.playNote(cl, msg); + } + } else { + cl.channel.playNote(cl, msg); + } + }) + cl.on('+ls', msg => { + if (!(cl.channel && cl.participantId)) return; + cl.server.roomlisteners.set(cl.connectionid, cl); + let rooms = []; + for (let room of Array.from(cl.server.rooms.values())) { + let data = room.fetchData().ch; + if (room.bans.get(cl.user._id)) { + data.banned = true; + } + if (room.settings.visible) rooms.push(data); + } + cl.sendArray([{ + "m": "ls", + "c": true, + "u": rooms + }]) + }) + cl.on('-ls', msg => { + if (!(cl.channel && cl.participantId)) return; + cl.server.roomlisteners.delete(cl.connectionid); + }) + cl.on("userset", msg => { + if (!cl.quotas.name.attempt()) return; + 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; + cl.user.name = msg.set.name; + let user = new User(cl); + user.getUserData().then((usr) => { + let dbentry = user.userdb.get(cl.user._id); + if (!dbentry) return; + dbentry.name = msg.set.name; + user.updatedb(); + cl.server.rooms.forEach((room) => { + room.updateParticipant(cl.participantId, { + name: msg.set.name + }); + }) + }) + + } + }) + cl.on('kickban', msg => { + if (!cl.quotas.kickban.attempt()) return; + if (!(cl.channel && cl.participantId)) return; + if (!(cl.user._id == cl.channel.crown.userId)) return; + if (msg.hasOwnProperty('_id') && typeof msg._id == "string") { + let _id = msg._id; + let ms = msg.ms || 0; + cl.channel.kickban(_id, ms); + } + }) + cl.on("bye", msg => { + cl.destroy(); + }) + cl.on("admin message", msg => { + if (!(cl.channel && cl.participantId)) return; + if (!msg.hasOwnProperty('password') || !msg.hasOwnProperty('msg')) return; + if (typeof msg.msg != 'object') return; + if (msg.password !== cl.server.adminpass) return; + cl.ws.emit("message", JSON.stringify([msg.msg]), true); + }) + //admin only stuff + /* + + List of admin only stuff + 1. admin_color + 2. admin_noteColor + 3. admin_chown + 4. admin_kickban + 5. admin_chset + + */ + cl.on('admin_color', (msg, admin) => { + if (!admin) return; + if (typeof cl.channel.verifyColor(msg.color) != 'string') return; + if (!msg.hasOwnProperty('id') && !msg.hasOwnProperty('_id')) return; + cl.server.connections.forEach((usr) => { + if ((usr.channel && usr.participantId && usr.user) && (usr.user._id == msg._id || (usr.participantId == msg.id))) { + let user = new User(usr); + user.cl.user.color = msg.color; + user.getUserData().then((uSr) => { + if (!uSr._id) return; + let dbentry = user.userdb.get(uSr._id); + if (!dbentry) return; + dbentry.color = msg.color; + dbentry.noteColor = msg.color; + //user.updatedb(); + cl.server.rooms.forEach((room) => { + room.updateParticipant(usr.participantId, { + color: msg.color, + noteColor: msg.color + }); + }) + }) + } + }) + + }) + cl.on('admin_noteColor', (msg, admin) => { + if (!admin) return; + if (typeof cl.channel.verifyColor(msg.color) != 'string') return; + if (!msg.hasOwnProperty('id') && !msg.hasOwnProperty('_id')) return; + cl.server.connections.forEach((usr) => { + if ((usr.channel && usr.participantId && usr.user) && (usr.user._id == msg._id || (usr.participantId == msg.id))) { + let user = new User(usr); + //user.getUserData().then((uSr) => { + //if (!uSr._id) return; + //let dbentry = user.userdb.get(uSr._id); + //if (!dbentry) return; + //dbentry.color = msg.color; + //user.updatedb(); + cl.server.rooms.forEach((room) => { + room.updateParticipant(usr.participantId, { + noteColor: msg.color + }); + }) + //}) + } + }) + + }) + cl.on("admin_chown", (msg, admin) => { + if (!admin) return; + if (msg.hasOwnProperty("id")) { + cl.channel.chown(msg.id); + console.log(msg.id); + } else { + cl.channel.chown(); + } + }) + cl.on('admin_kickban', (msg, admin) => { + if (!admin) return; + if (msg.hasOwnProperty('_id') && typeof msg._id == "string") { + let _id = msg._id; + let ms = msg.ms || 0; + cl.channel.kickban(_id, ms); + } + }) + cl.on("admin_chset", (msg, admin) => { + if (!admin) return; + if (!msg.hasOwnProperty("set") || !msg.set) msg.set = cl.channel.verifySet(cl.channel._id,{}); + cl.channel.settings = msg.set; + cl.channel.updateCh(); + }) + cl.on("admin_notification", (msg, admin) => { + if (!admin) return; + cl.channel.Notification(msg.content); + console.log(msg.content); + }) +} \ No newline at end of file diff --git a/src/Quota.js b/src/Quota.js new file mode 100644 index 0000000..a3b303a --- /dev/null +++ b/src/Quota.js @@ -0,0 +1,58 @@ +function RateLimit(a,b){ + this.a = b.a || 1; + this.m = b.m || 10; + this.mh = b.mh || 3; + this.setParams(a,{a:this.a,m:this.m,mh:this.mh}); + this.resetPoints(); + if(a !== null){ + var self = this; + this.giveInt = setInterval(()=>{self.give()},a); + }; +}; +RateLimit.prototype.setParams = function(a,b){ + var a = b.a || this.a || 1; + var m = b.m || this.m || 5; + var mh = b.mh || this.mh || 3; + clearInterval(this.giveInt); + this.giveInt = undefined; + if(a !== this.a || m !== this.m || mh !== this.mh){ + this.a = a; + this.m = m; + this.mh = mh; + this.resetPoints(); + if(a !== null){ + var self = this; + this.giveInt = setInterval(()=>{self.give()},a); + }; + return true; + }; + return false; +}; +RateLimit.prototype.resetPoints = function(){ + this.points = this.m; + this.history = []; + for(var i=0; i this.m) this.points = this.m; + }; +}; +RateLimit.prototype.spend = function(needed){ + var sum = 0; + for(var i in this.history){ + sum += this.history[i]; + }; + if(sum <= 0) needed *= this.a; + if(this.points < needed){ + return false; + }else{ + this.points -= needed; + return true; + }; +}; + +module.exports = RateLimit; \ No newline at end of file diff --git a/src/Ratelimit.js b/src/Ratelimit.js new file mode 100644 index 0000000..8d27edc --- /dev/null +++ b/src/Ratelimit.js @@ -0,0 +1,40 @@ + +var RateLimit = function(interval_ms) { + this._interval_ms = interval_ms || 0; // (0 means no limit) + this._after = 0; +}; + +RateLimit.prototype.attempt = function(time) { + var time = time || Date.now(); + if(time < this._after) return false; + this._after = time + this._interval_ms; + return true; +}; + +RateLimit.prototype.setInterval = function(interval_ms) { + this._after += interval_ms - this._interval_ms; + this._interval_ms = interval_ms; +}; + +var RateLimitChain = function(num, interval_ms) { + this.setNumAndInterval(num, interval_ms); +}; + +RateLimitChain.prototype.attempt = function(time) { + var time = time || Date.now(); + for(var i = 0; i < this._chain.length; i++) { + if(this._chain[i].attempt(time)) return true; + } + return false; +}; + +RateLimitChain.prototype.setNumAndInterval = function(num, interval_ms) { + this._chain = []; + for(var i = 0; i < num; i++) { + this._chain.push(new RateLimit(interval_ms)); + } +}; + +var exports = typeof module !== "undefined" ? module.exports : this; +exports.RateLimit = RateLimit; +exports.RateLimitChain = RateLimitChain; \ No newline at end of file diff --git a/src/Room.js b/src/Room.js new file mode 100644 index 0000000..4998b9f --- /dev/null +++ b/src/Room.js @@ -0,0 +1,432 @@ +//array of rooms +//room class +//room deleter +//databases in Map + +class Room extends EventEmitter { + constructor(server, _id, settings) { + super(); + EventEmitter.call(this); + this._id = _id; + this.server = server; + this.crown = null; + this.crowndropped = false; + this.settings = this.verifySet(this._id,{set:settings}); + this.chatmsgs = []; + this.ppl = new Map(); + this.connections = []; + this.bindEventListeners(); + this.server.rooms.set(_id, this); + this.bans = new Map(); + } + join(cl) { //this stuff is complicated + let otheruser = this.connections.find((a) => a.user._id == cl.user._id) + if (!otheruser) { + let participantId = createKeccakHash('keccak256').update((Math.random().toString() + cl.ip)).digest('hex').substr(0, 24); + cl.user.id = participantId; + cl.participantId = participantId; + if (((this.connections.length == 0 && Array.from(this.ppl.values()).length == 0) && !this.isLobby(this._id)) || this.crown && (this.crown.userId == cl.user._id)) { //user that created the room, give them the crown. + this.crown = { + participantId: cl.participantId, + userId: cl.user._id, + time: Date.now(), + startPos: { + x: 50, + y: 50 + }, + endPos: { + x: this.getCrownX(), + y: this.getCrownY() + } + } + this.crowndropped = false; + } + this.ppl.set(participantId, cl); + this.connections.push(cl); + 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, + 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) + }]) + this.updateCh(cl); + } else { + cl.user.id = otheruser.participantId; + cl.participantId = otheruser.participantId; + this.connections.push(cl); + cl.sendArray([{ + m: "c", + c: this.chatmsgs.slice(-1 * 32) + }]) + this.updateCh(cl); + } + + } + remove(p) { //this is complicated too + let otheruser = this.connections.filter((a) => a.user._id == p.user._id); + if (!(otheruser.length > 1)) { + this.ppl.delete(p.participantId); + this.connections.splice(this.connections.findIndex((a) => a.connectionid == p.connectionid), 1); + console.log(`Deleted client ${p.user.id}`); + this.sendArray([{ + m: "bye", + p: p.participantId + }], p, false); + if (this.crown) + if (this.crown.userId == p.user._id && !this.crowndropped) { + this.chown(); + } + this.updateCh(); + } else { + this.connections.splice(this.connections.findIndex((a) => a.connectionid == p.connectionid), 1); + } + + } + updateCh(cl) { //update channel for all people in channel + if (Array.from(this.ppl.values()).length <= 0) this.destroy(); + this.connections.forEach((usr) => { + this.server.connections.get(usr.connectionid).sendArray([this.fetchData(usr, cl)]) + }) + this.server.updateRoom(this.fetchData()); + } + updateParticipant(pid, options) { + let p = this.ppl.get(pid); + if (!p) return; + options.name ? this.ppl.get(pid).user.name = options.name : {}; + options._id ? this.ppl.get(pid).user._id = options._id : {}; + options.color ? this.ppl.get(pid).user.color = options.color : {}; + options.noteColor ? this.ppl.get(pid).user.noteColor = options.noteColor : {}; + this.connections.filter((ofo) => ofo.participantId == p.participantId).forEach((usr) => { + options.name ? usr.user.name = options.name : {}; + options._id ? usr.user._id = options._id : {}; + options.color ? usr.user.color = options.color : {}; + options.noteColor ? usr.user.noteColor = options.noteColor : {}; + }) + this.sendArray([{ + color: p.user.color, + noteColor: p.user.noteColor, + //noteColor: "#000", + id: p.participantId, + m: "p", + name: p.user.name, + x: p.x || 200, + y: p.y || 100, + _id: p.user._id + }]) + } + destroy() { //destroy room + this._id; + console.log(`Deleted room ${this._id}`); + this.settings = {}; + this.ppl; + this.connnections; + this.chatmsgs; + this.server.rooms.delete(this._id); + } + sendArray(arr, not, onlythisparticipant) { + this.connections.forEach((usr) => { + if (!not || (usr.participantId != not.participantId && !onlythisparticipant) || (usr.connectionid != not.connectionid && onlythisparticipant)) { + try { + this.server.connections.get(usr.connectionid).sendArray(arr) + } catch (e) { + console.log(e); + } + } + }) + } + fetchData(usr, cl) { + let chppl = []; + [...this.ppl.values()].forEach((a) => { + chppl.push(a.user); + }) + let data = { + m: "ch", + p: "ofo", + ch: { + count: chppl.length, + crown: this.crown, + settings: this.settings, + _id: this._id + }, + ppl: chppl + } + if (cl) { + if (usr.connectionid == cl.connectionid) { + data.p = cl.participantId; + } else { + delete data.p; + } + } else { + delete data.p; + } + if (data.ch.crown == null) { + delete data.ch.crown; + } else { + + } + return data; + } + verifyColor(strColor){ + var test2 = /^#[0-9A-F]{6}$/i.test(strColor); + if(test2 == true){ + return strColor; + } else{ + return false; + } + } + isLobby(_id) { + if (_id.startsWith("lobby")) { + let lobbynum = _id.split("lobby")[1]; + if (_id == "lobby") { + return true; + } + if (!(parseInt(lobbynum).toString() == lobbynum)) return false; + for (let i in lobbynum) { + if (parseInt(lobbynum[i]) >= 0) { + if (parseInt(i) + 1 == lobbynum.length) return true; + + } else { + return false; + } + } + } else if (_id.startsWith("test/")) { + if (_id == "test/") { + return false; + } else { + return true; + } + } else { + return false; + } + + } + getCrownY() { + return 50 - 30; + } + getCrownX() { + return 50; + } + chown(id) { + let prsn = this.ppl.get(id); + if (prsn) { + this.crown = { + participantId: prsn.participantId, + userId: prsn.user._id, + time: Date.now(), + startPos: { + x: 50, + y: 50 + }, + endPos: { + x: this.getCrownX(), + y: this.getCrownY() + }, + } + this.crowndropped = false; + } else { + this.crown = { + userId: this.crown.userId, + time: Date.now(), + startPos: { + x: 50, + y: 50 + }, + endPos: { + x: this.getCrownX(), + y: this.getCrownY() + } + } + this.crowndropped = true; + } + this.updateCh(); + } + setCords(p, x, y) { + if (p.participantId && this.ppl.get(p.participantId)) { + x ? this.ppl.get(p.participantId).x = x : {}; + y ? this.ppl.get(p.participantId).y = y : {}; + this.sendArray([{ + m: "m", + id: p.participantId, + x: this.ppl.get(p.participantId).x, + y: this.ppl.get(p.participantId).y + }], p, false); + } + } + chat(p, msg) { + if (msg.message.length > 512) return; + let filter = ["AMIGHTYWIND"]; + let regexp = new RegExp("\\b(" + filter.join("|") + ")\\b", "i"); + if (regexp.test(msg.message)) return; + let prsn = this.ppl.get(p.participantId); + if (prsn) { + let message = {}; + message.m = "a"; + message.a = msg.message; + message.p = { + color: p.user.color, + id: p.participantId, + name: p.user.name, + _id: p.user._id + }; + message.t = Date.now(); + this.sendArray([message]); + this.chatmsgs.push(message); + } + } + playNote(cl, note) { + this.sendArray([{ + m: "n", + n: note.n, + p: cl.participantId, + t: note.t + }], cl, true); + } + sendNotequota(allowance = 200, max = 600, maxHistLen = 3){ + this.sendArray([{ + m: 'nq', + allowance: allowance, + max: max, + maxHistLen: maxHistLen + }]) + } + kickban(_id, ms) { + ms = parseInt(ms); + if (ms >= (1000 * 60 * 60 - 500)) return; + if (ms < 0) return; + ms = Math.round(ms / 1000) * 1000; + let user = this.connections.find((usr) => usr.user._id == _id); + if (!user) return; + let asd = true; + let tonc = true; + let pthatbanned = this.ppl.get(this.crown.participantId); + this.connections.filter((usr) => usr.participantId == user.participantId).forEach((u) => { + user.bantime = Math.floor(Math.floor(ms / 1000) / 60); + user.bannedtime = Date.now(); + user.msbanned = ms; + this.bans.set(user.user._id, user); + if (this.crown && (this.crown.userId)) { + u.setChannel("test/awkward", {}); + if (asd) + this.Notification(user.user._id, + "Notice", + `Banned from \"${this._id}\" for ${Math.floor(Math.floor(ms / 1000) / 60)} minutes.`, + "", + 7000, + "#room", + "short" + ) + if (asd) + this.Notification("room", + "Notice", + `${pthatbanned.user.name} banned ${user.user.name} from the channel for ${Math.floor(Math.floor(ms / 1000) / 60)} minutes.`, + "", + 7000, + "#room", + "short" + ) + if (this.crown && (this.crown.userId == _id) && tonc) { + this.Notification("room", + "Certificate of Award", + `Let it be known that ${user.user.name} kickbanned him/her self.`, + "", + 7000, + "#room" + ); + tonc = false; + } + + } + + }) + } + Notification(who, title, text, html, duration, target, klass, id) { + let obj = { + m: "notification", + title: title, + text: text, + html: html, + target: target, + duration: duration, + class: klass, + id: id + }; + if (!id) delete obj.id; + if (!title) delete obj.title; + if (!text) delete obj.text; + if (!html) delete obj.html; + if (!target) delete obj.target; + if (!duration) delete obj.duration; + if (!klass) delete obj.class; + switch (who) { + case "all": { + for (let con of Array.from(this.server.connections.values())) { + con.sendArray([obj]); + } + break; + } + case "room": { + for (let con of this.connections) { + con.sendArray([obj]); + } + break; + } + default: { + Array.from(this.server.connections.values()).filter((usr) => usr.user._id == who).forEach((p) => { + p.sendArray([obj]); + }); + } + } + } + bindEventListeners() { + this.on("bye", participant => { + this.remove(participant); + }) + + this.on("m", (participant, x, y) => { + this.setCords(participant, x, y); + }) + + this.on("a", (participant, msg) => { + this.chat(participant, msg); + }) + } + verifySet(_id,msg){ + if(!isObj(msg.set)) msg.set = {visible:true,color:this.server.defaultRoomColor,chat:true,crownsolo:false}; + if(isBool(msg.set.lobby)){ + if(!this.isLobby(_id)) delete msg.set.lobby; // keep it nice and clean + }else{ + if(this.isLobby(_id)) msg.set = {visible:true,color:this.server.defaultLobbyColor,color2:this.server.defaultLobbyColor2,chat:true,crownsolo:false,lobby:true}; + } + if(!isBool(msg.set.visible)){ + if(msg.set.visible == undefined) msg.set.visible = (!isObj(this.settings) ? true : this.settings.visible); + else msg.set.visible = true; + }; + if(!isBool(msg.set.chat)){ + if(msg.set.chat == undefined) msg.set.chat = (!isObj(this.settings) ? true : this.settings.chat); + else msg.set.chat = true; + }; + if(!isBool(msg.set.crownsolo)){ + if(msg.set.crownsolo == undefined) msg.set.crownsolo = (!isObj(this.settings) ? false : this.settings.crownsolo); + else msg.set.crownsolo = false; + }; + if(!isString(msg.set.color) || !/^#[0-9a-f]{6}$/i.test(msg.set.color)) msg.set.color = (!isObj(this.settings) ? this.server.defaultRoomColor : this.settings.color); + if(isString(msg.set.color2)){ + if(!/^#[0-9a-f]{6}$/i.test(msg.set.color2)){ + if(this.settings){ + if(this.settings.color2) msg.set.color2 = this.settings.color2; + else delete msg.set.color2; // keep it nice and clean + } + } + }; + return msg.set; + } + +} +module.exports = Room; diff --git a/src/Server.js b/src/Server.js new file mode 100644 index 0000000..fae58ce --- /dev/null +++ b/src/Server.js @@ -0,0 +1,45 @@ +const Client = require("./Client.js"); +const banned = require('../banned.json'); + +class Server extends EventEmitter { + constructor(config) { + super(); + EventEmitter.call(this); + this.wss = new WebSocket.Server({ + port: config.port, + backlog: 100, + verifyClient: (info) => { + //if (banned.includes(info.req.headers['x-forwarded-for'].split(",")[0].replace('::ffff:', ''))) return false; + if (banned.includes((info.req.connection.remoteAddress).replace("::ffff:", ""))) return false; + return true; + } + }); + this.connectionid = 0; + this.connections = new Map(); + this.roomlisteners = new Map(); + this.rooms = new Map(); + this.wss.on('connection', (ws, req) => { + this.connections.set(++this.connectionid, new Client(ws, req, this)); + }); + this.legit_m = ["a", "bye", "hi", "ch", "+ls", "-ls", "m", "n", "devices", "t", "chset", "userset", "chown", "kickban", "admin message", "color"] + this.welcome_motd = config.motd || "You agree to read this message."; + this._id_Private_Key = config._id_PrivateKey || "boppity"; + this.defaultUsername = config.defaultUsername || "Anonymous"; + this.defaultRoomColor = config.defaultRoomColor || "#3b5054"; + this.defaultLobbyColor = config.defaultLobbyColor || "#19b4b9"; + this.defaultLobbyColor2 = config.defaultLobbyColor2 || "#801014"; + this.adminpass = config.adminpass || "Bop It"; + }; + updateRoom(data) { + if (!data.ch.settings.visible) return; + for (let cl of Array.from(this.roomlisteners.values())) { + cl.sendArray([{ + "m": "ls", + "c": false, + "u": [data.ch] + }]) + } + } +} + +module.exports = Server; \ No newline at end of file diff --git a/src/TODO.txt b/src/TODO.txt new file mode 100644 index 0000000..f9af52b --- /dev/null +++ b/src/TODO.txt @@ -0,0 +1,2 @@ + +Room.js make color verifier diff --git a/src/User.js b/src/User.js new file mode 100644 index 0000000..7c4a960 --- /dev/null +++ b/src/User.js @@ -0,0 +1,56 @@ +const ColorEncoder = require("./ColorEncoder.js"); +const { promisify } = require('util'); +let userdb; +class User { + constructor(cl) { + this.cl = cl; + this.server = this.cl.server; + this.userdb = userdb; + this.default_db = {}; + } + async getUserData() { + if (!userdb || (userdb instanceof Map && [...userdb.entries()] == [])) { + await this.setUpDb(); + } + let _id = createKeccakHash('keccak256').update((this.cl.server._id_Private_Key + this.cl.ip)).digest('hex').substr(0, 24); + //console.log("CONNECTED IP: " + this.cl.ip); + let usertofind = userdb.get(_id); + if (!usertofind) { + if (typeof usertofind == 'object' && (usertofind.hasOwnProperty('name') && usertofind.name != this.server.defaultUsername)) return; + userdb.set(_id, { + "color": `#${ColorEncoder.intToRGB(ColorEncoder.hashCode(_id)).toLowerCase()}`, + "noteColor": `#${ColorEncoder.intToRGB(ColorEncoder.hashCode(_id)).toLowerCase()}`, + "name": this.server.defaultUsername, + "_id": _id, + "ip": this.cl.ip + }); + this.updatedb(); + } + let user = userdb.get(_id); + return { + "color": user.color, + "noteColor": user.noteColor, + "name": user.name, + "_id": user._id, + } + } + async updatedb() { + const writeFile = promisify(fs.writeFile); + await writeFile('src/db/users.json', JSON.stringify(User.strMapToObj(userdb), null, 2)); + } + async setUpDb() { + const writeFile = promisify(fs.writeFile); + const readdir = promisify(fs.readdir); + let files = await readdir("src/db/"); + if (!files.includes("users.json")) { + await writeFile('src/db/users.json', JSON.stringify(this.default_db, null, 2)) + userdb = new Map(Object.entries(require("./db/users.json"))); + } else { + userdb = new Map(Object.entries(require("./db/users.json"))); + } + } + static strMapToObj(strMap) { + return [...strMap.entries()].reduce((obj, [key, value]) => (obj[key] = value, obj), {}); + } +} +module.exports = User; \ No newline at end of file diff --git a/src/db/users.json b/src/db/users.json new file mode 100644 index 0000000..50dd7fe --- /dev/null +++ b/src/db/users.json @@ -0,0 +1,114 @@ +{ + "9c9f38bad2839d9e33f29361": { + "color": "#4cff5c", + "noteColor": "#4cff5c", + "name": "Anonymous", + "_id": "9c9f38bad2839d9e33f29361", + "ip": "68.72.101.149" + }, + "77e4cce49134dcc22f9db512": { + "color": "#e4a438", + "noteColor": "#e4a438", + "name": "Anonymous", + "_id": "77e4cce49134dcc22f9db512", + "ip": "94.15.73.43" + }, + "b8d6f3f34a1f412751a3cb13": { + "color": "#de3a55", + "noteColor": "#de3a55", + "name": "Wolfy", + "_id": "b8d6f3f34a1f412751a3cb13", + "ip": "67.141.166.70" + }, + "a2e7d9f15b88609743493790": { + "color": "#0b4667", + "noteColor": "#0b4667", + "name": "☯️ エラ ー 4̴͓̍ ̴̝̿0̵̨̒ ̵̤͊4̴̒", + "_id": "a2e7d9f15b88609743493790", + "ip": "98.182.142.78" + }, + "ca111f51c16dd98dabd3773c": { + "color": "#56da2c", + "noteColor": "#56da2c", + "name": "Rudra", + "_id": "ca111f51c16dd98dabd3773c", + "ip": "75.104.54.115" + }, + "74d18d3afb8646ae5dbe45ef": { + "color": "#2a90b8", + "noteColor": "#2a90b8", + "name": "ALLAH sad :(", + "_id": "74d18d3afb8646ae5dbe45ef", + "ip": "198.16.76.28" + }, + "0f726efbbcac60b92bf8d708": { + "color": "#b54d8d", + "noteColor": "#b54d8d", + "name": "Anonymous", + "_id": "0f726efbbcac60b92bf8d708", + "ip": "191.35.208.102" + }, + "78dbd1290e535af94d3a5357": { + "color": "#20a563", + "noteColor": "#20a563", + "name": "Rudra", + "_id": "78dbd1290e535af94d3a5357", + "ip": "198.16.74.45" + }, + "d86fa3780fbae7ab5f4b01a2": { + "color": "#836e90", + "noteColor": "#836e90", + "name": "๖ۣۜ 𝑜𝓌𝓁𝓌𝒶𝓉𝒸𝒽🦉👀", + "_id": "d86fa3780fbae7ab5f4b01a2", + "ip": "198.16.66.125" + }, + "990d86b045a8a08345b75699": { + "color": "#a7b719", + "noteColor": "#a7b719", + "name": "Qhy 「 qhy!help 」", + "_id": "990d86b045a8a08345b75699", + "ip": "54.80.91.103" + }, + "73f36b73136cc3950c4ba6ff": { + "color": "#f09d22", + "noteColor": "#f09d22", + "name": "Anonymous", + "_id": "73f36b73136cc3950c4ba6ff", + "ip": "198.16.66.195" + }, + "eec94ceb5ff11a4b1b176280": { + "color": "#1f00e7", + "noteColor": "#1f00e7", + "name": "Qhy ", + "_id": "eec94ceb5ff11a4b1b176280", + "ip": "52.87.215.231" + }, + "98bc89e0ae747d9e1375a16e": { + "color": "#26d0c5", + "noteColor": "#26d0c5", + "name": "Qhy ", + "_id": "98bc89e0ae747d9e1375a16e", + "ip": "54.144.133.13" + }, + "8755e2600aa043273aac482a": { + "color": "#0c4c4d", + "noteColor": "#0c4c4d", + "name": "Qhy ", + "_id": "8755e2600aa043273aac482a", + "ip": "34.233.126.13" + }, + "a6a35eb1546b541be5f11cc8": { + "color": "#d3de03", + "noteColor": "#d3de03", + "name": "Anonymous", + "_id": "a6a35eb1546b541be5f11cc8", + "ip": "177.18.157.8" + }, + "651d3e63d8a738ac1a40ed9f": { + "color": "#ca14aa", + "noteColor": "#ca14aa", + "name": "Anonymous", + "_id": "651d3e63d8a738ac1a40ed9f", + "ip": "77.111.247.71" + } +} \ No newline at end of file From 39780a25a70fe6b13d6771d7b4830ca7f342edf3 Mon Sep 17 00:00:00 2001 From: Wolfy Date: Tue, 7 Apr 2020 03:56:16 -0400 Subject: [PATCH 026/135] oops --- banned.json | 4 ++-- config.js | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/banned.json b/banned.json index 1610ea1..75d98b2 100644 --- a/banned.json +++ b/banned.json @@ -1,3 +1,3 @@ [ - -] \ No newline at end of file + "1.2.3.4" +] diff --git a/config.js b/config.js index e27916c..84ce5f7 100644 --- a/config.js +++ b/config.js @@ -6,5 +6,5 @@ module.exports = Object.seal({ "defaultRoomColor": "#3b5054", "defaultLobbyColor": "#19b4b9", "defaultLobbyColor2": "#801014", - "adminpass": "27PP6YLTxg0b1P2B8eGSOki1" -}) \ No newline at end of file + "adminpass": "adminpass" +}) From e47b7999ab94bb04133f158cf0ac64c584589b2c Mon Sep 17 00:00:00 2001 From: wolfy01 <45273698+wolfy01@users.noreply.github.com> Date: Tue, 7 Apr 2020 03:59:50 -0400 Subject: [PATCH 027/135] Delete TODO.txt --- src/TODO.txt | 2 -- 1 file changed, 2 deletions(-) delete mode 100644 src/TODO.txt diff --git a/src/TODO.txt b/src/TODO.txt deleted file mode 100644 index f9af52b..0000000 --- a/src/TODO.txt +++ /dev/null @@ -1,2 +0,0 @@ - -Room.js make color verifier From 1362d7946fd7ff47f0a55035db31d51bc5a185d8 Mon Sep 17 00:00:00 2001 From: wolfy01 <45273698+wolfy01@users.noreply.github.com> Date: Tue, 7 Apr 2020 04:01:05 -0400 Subject: [PATCH 028/135] Create TODO.txt --- TODO.txt | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 TODO.txt diff --git a/TODO.txt b/TODO.txt new file mode 100644 index 0000000..da4291c --- /dev/null +++ b/TODO.txt @@ -0,0 +1,3 @@ +1. Send noteQuota on room owner change. +2. Add noteQuota server side. +3. Room.js make color verifier From 1c72ccf885819cdbabad97207c343b9d146bcf80 Mon Sep 17 00:00:00 2001 From: wolfy01 <45273698+wolfy01@users.noreply.github.com> Date: Tue, 7 Apr 2020 04:01:23 -0400 Subject: [PATCH 029/135] Rename TODO.txt to TODO.md --- TODO.txt => TODO.md | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename TODO.txt => TODO.md (100%) diff --git a/TODO.txt b/TODO.md similarity index 100% rename from TODO.txt rename to TODO.md From cc6dcbacf4212f66d42b45a6d9ea09c61cca8733 Mon Sep 17 00:00:00 2001 From: wolfy01 <45273698+wolfy01@users.noreply.github.com> Date: Tue, 7 Apr 2020 04:03:45 -0400 Subject: [PATCH 030/135] Change path to config Oops... --- src/Message.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Message.js b/src/Message.js index c62d304..c87041e 100644 --- a/src/Message.js +++ b/src/Message.js @@ -1,4 +1,4 @@ -const config = require('./db/config'); +const config = require('../config'); const quotas = config.quotas; const User = require("./User.js"); module.exports = (cl) => { @@ -251,4 +251,4 @@ module.exports = (cl) => { cl.channel.Notification(msg.content); console.log(msg.content); }) -} \ No newline at end of file +} From a8502f4adf9a8c06ad5a3176bc5824890689e6b9 Mon Sep 17 00:00:00 2001 From: wolfy01 <45273698+wolfy01@users.noreply.github.com> Date: Tue, 7 Apr 2020 04:05:13 -0400 Subject: [PATCH 031/135] Welp... forgot we didn't need that anyways --- src/Message.js | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/Message.js b/src/Message.js index c87041e..b393f2e 100644 --- a/src/Message.js +++ b/src/Message.js @@ -1,5 +1,4 @@ -const config = require('../config'); -const quotas = config.quotas; +const quotas = require('../Quotas'); const User = require("./User.js"); module.exports = (cl) => { cl.once("hi", () => { From d5d8a7ff1add59d9e213a52bef41e2c98cd40b69 Mon Sep 17 00:00:00 2001 From: wolfy01 <45273698+wolfy01@users.noreply.github.com> Date: Tue, 7 Apr 2020 04:21:45 -0400 Subject: [PATCH 032/135] Don't send noteQuota to all clients! --- src/Room.js | 8 -------- 1 file changed, 8 deletions(-) diff --git a/src/Room.js b/src/Room.js index 4998b9f..5606217 100644 --- a/src/Room.js +++ b/src/Room.js @@ -288,14 +288,6 @@ class Room extends EventEmitter { t: note.t }], cl, true); } - sendNotequota(allowance = 200, max = 600, maxHistLen = 3){ - this.sendArray([{ - m: 'nq', - allowance: allowance, - max: max, - maxHistLen: maxHistLen - }]) - } kickban(_id, ms) { ms = parseInt(ms); if (ms >= (1000 * 60 * 60 - 500)) return; From 237139d715dc91b3dc4d68021d918e8c9920270f Mon Sep 17 00:00:00 2001 From: wolfy01 <45273698+wolfy01@users.noreply.github.com> Date: Tue, 7 Apr 2020 04:22:48 -0400 Subject: [PATCH 033/135] Right way to send noteQuota to client --- src/Message.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Message.js b/src/Message.js index b393f2e..7cf8870 100644 --- a/src/Message.js +++ b/src/Message.js @@ -29,12 +29,12 @@ module.exports = (cl) => { if (msg._id.length > 512) return; cl.setChannel(msg._id, msg.set); if (cl.channel.isLobby(cl.channel._id)) { - cl.channel.sendNotequota(quotas.note.lobby.allowance, quotas.note.lobby.max, quotas.note.lobby.maxHistLen); + cl.sendArray([{m: 'nq', allowance: quotas.note.lobby.allowance, max: quotas.note.lobby.max, maxHistLen: quotas.note.lobby.maxHistLen}]) } else { if (!(cl.user._id == cl.channel.crown.userId)) { - cl.channel.sendNotequota(quotas.note.normal.allowance, quotas.note.normal.max, quotas.note.normal.maxHistLen); + cl.sendArray([{m: 'nq', allowance: quotas.note.normal.allowance, max: quotas.note.normal.max, maxHistLen: quotas.note.normal.maxHistLen}]) } else { - cl.channel.sendNotequota(quotas.note.insane.allowance, quotas.note.insane.max, quotas.note.insane.maxHistLen); + cl.sendArray([{m: 'nq', allowance: quotas.note.insane.allowance, max: quotas.note.insane.max, maxHistLen: quotas.note.insane.maxHistLen}]) } } } From dda2549a144425e03f844a97e53c2e608fa9d0e7 Mon Sep 17 00:00:00 2001 From: Wolfy Date: Tue, 7 Apr 2020 13:03:36 -0400 Subject: [PATCH 034/135] Quotas Make quotas ip based. Clients now can not bypass quota by having more than 1 client --- src/Client.js | 16 ---------------- src/Message.js | 28 +++++++++++++++------------- src/User.js | 22 ++++++++++++++++++++++ src/db/users.json | 21 +++++++++++++++++++++ 4 files changed, 58 insertions(+), 29 deletions(-) diff --git a/src/Client.js b/src/Client.js index d3c4f32..c762e68 100644 --- a/src/Client.js +++ b/src/Client.js @@ -1,6 +1,3 @@ -const quotas = require('../Quotas'); -const RateLimit = require('./RateLimit.js').RateLimit; -const RateLimitChain = require('./RateLimit.js').RateLimitChain; const Room = require("./Room.js"); require('node-json-color-stringify'); class Client extends EventEmitter { @@ -17,19 +14,6 @@ class Client extends EventEmitter { this.ip = (req.connection.remoteAddress).replace("::ffff:", ""); this.destroied = false; this.bindEventListeners(); - this.quotas = { - //note: new limiter(2000, { allowance:3000, max:24000, maxHistLen:3}), - chat: { - lobby: new RateLimitChain(quotas.chat.lobby.amount, quotas.chat.lobby.time), - normal: new RateLimitChain(quotas.chat.normal.amount, quotas.chat.normal.time), - insane: new RateLimitChain(quotas.chat.insane.amount, quotas.chat.insane.time) - }, - name: new RateLimitChain(quotas.name.amount, quotas.name.time), - room: new RateLimit(quotas.room.time), - chown: new RateLimitChain(quotas.chown.amount, quotas.chown.time), - cursor: new RateLimit(quotas.cursor.time), - kickban: new RateLimitChain(quotas.kickban.amount, quotas.kickban.time), - } require('./Message.js')(this); } isConnected() { diff --git a/src/Message.js b/src/Message.js index 7cf8870..1d8d319 100644 --- a/src/Message.js +++ b/src/Message.js @@ -1,4 +1,5 @@ -const quotas = require('../Quotas'); +const NoteQuotas = require('../Quotas'); +let quotas; const User = require("./User.js"); module.exports = (cl) => { cl.once("hi", () => { @@ -12,6 +13,7 @@ module.exports = (cl) => { msg.v = "Beta"; cl.sendArray([msg]) cl.user = data; + quotas = cl.server.connections[cl.user._id].quotas; }) }) cl.on("t", msg => { @@ -23,24 +25,24 @@ module.exports = (cl) => { }]) }) cl.on("ch", msg => { - if (!cl.quotas.room.attempt()) return; + if (!quotas.room.attempt()) return; if (!msg.hasOwnProperty("set") || !msg.set) msg.set = {}; if (msg.hasOwnProperty("_id") && typeof msg._id == "string") { if (msg._id.length > 512) return; cl.setChannel(msg._id, msg.set); if (cl.channel.isLobby(cl.channel._id)) { - cl.sendArray([{m: 'nq', allowance: quotas.note.lobby.allowance, max: quotas.note.lobby.max, maxHistLen: quotas.note.lobby.maxHistLen}]) + cl.sendArray([{m: 'nq', allowance: NoteQuotas.note.lobby.allowance, max: NoteQuotas.note.lobby.max, maxHistLen: NoteQuotas.note.lobby.maxHistLen}]) } else { if (!(cl.user._id == cl.channel.crown.userId)) { - cl.sendArray([{m: 'nq', allowance: quotas.note.normal.allowance, max: quotas.note.normal.max, maxHistLen: quotas.note.normal.maxHistLen}]) + cl.sendArray([{m: 'nq', allowance: NoteQuotas.note.normal.allowance, max: NoteQuotas.note.normal.max, maxHistLen: NoteQuotas.note.normal.maxHistLen}]) } else { - cl.sendArray([{m: 'nq', allowance: quotas.note.insane.allowance, max: quotas.note.insane.max, maxHistLen: quotas.note.insane.maxHistLen}]) + cl.sendArray([{m: 'nq', allowance: NoteQuotas.note.insane.allowance, max: NoteQuotas.note.insane.max, maxHistLen: NoteQuotas.note.insane.maxHistLen}]) } } } }) cl.on("m", msg => { - if (!cl.quotas.cursor.attempt()) return; + if (!quotas.cursor.attempt()) return; if (!(cl.channel && cl.participantId)) return; if (!msg.hasOwnProperty("x")) msg.x = null; if (!msg.hasOwnProperty("y")) msg.y = null; @@ -50,7 +52,7 @@ module.exports = (cl) => { }) cl.on("chown", msg => { - if (!cl.quotas.chown.attempt()) return; + if (!quotas.chown.attempt()) return; if (!(cl.channel && cl.participantId)) return; //console.log((Date.now() - cl.channel.crown.time)) //console.log(!(cl.channel.crown.userId != cl.user._id), !((Date.now() - cl.channel.crown.time) > 15000)); @@ -73,12 +75,12 @@ module.exports = (cl) => { }) cl.on("a", msg => { if (cl.channel.isLobby(cl.channel._id)) { - if (!cl.quotas.chat.lobby.attempt()) return; + if (!quotas.chat.lobby.attempt()) return; } else { if (!(cl.user._id == cl.channel.crown.userId)) { - if (!cl.quotas.chat.normal.attempt()) return; + if (!quotas.chat.normal.attempt()) return; } else { - if (!cl.quotas.chat.insane.attempt()) return; + if (!quotas.chat.insane.attempt()) return; } } if (!(cl.channel && cl.participantId)) return; @@ -121,7 +123,7 @@ module.exports = (cl) => { cl.server.roomlisteners.delete(cl.connectionid); }) cl.on("userset", msg => { - if (!cl.quotas.name.attempt()) return; + if (!quotas.name.attempt()) return; if (!(cl.channel && cl.participantId)) return; if (!msg.hasOwnProperty("set") || !msg.set) msg.set = {}; if (msg.set.hasOwnProperty('name') && typeof msg.set.name == "string") { @@ -143,7 +145,7 @@ module.exports = (cl) => { } }) cl.on('kickban', msg => { - if (!cl.quotas.kickban.attempt()) return; + if (!quotas.kickban.attempt()) return; if (!(cl.channel && cl.participantId)) return; if (!(cl.user._id == cl.channel.crown.userId)) return; if (msg.hasOwnProperty('_id') && typeof msg._id == "string") { @@ -250,4 +252,4 @@ module.exports = (cl) => { cl.channel.Notification(msg.content); console.log(msg.content); }) -} +} \ No newline at end of file diff --git a/src/User.js b/src/User.js index 7c4a960..a1a43fc 100644 --- a/src/User.js +++ b/src/User.js @@ -1,3 +1,6 @@ +const quotas = require('../Quotas'); +const RateLimit = require('./RateLimit.js').RateLimit; +const RateLimitChain = require('./RateLimit.js').RateLimitChain; const ColorEncoder = require("./ColorEncoder.js"); const { promisify } = require('util'); let userdb; @@ -13,6 +16,25 @@ class User { await this.setUpDb(); } let _id = createKeccakHash('keccak256').update((this.cl.server._id_Private_Key + this.cl.ip)).digest('hex').substr(0, 24); + if(this.server.connections[_id]){ // Connection rate quota? + //if(this.connectionsObjects[_id].connections.length < 10) this.connectionsObjects[_id].connections.push({room:undefined,ws:ws,cl:new Connection(ws)}); + }else{ + this.server.connections[_id] = { + quotas:{ + //note: new limiter(2000, { allowance:3000, max:24000, maxHistLen:3}), + chat: { + lobby: new RateLimitChain(quotas.chat.lobby.amount, quotas.chat.lobby.time), + normal: new RateLimitChain(quotas.chat.normal.amount, quotas.chat.normal.time), + insane: new RateLimitChain(quotas.chat.insane.amount, quotas.chat.insane.time) + }, + name: new RateLimitChain(quotas.name.amount, quotas.name.time), + room: new RateLimit(quotas.room.time), + chown: new RateLimitChain(quotas.chown.amount, quotas.chown.time), + cursor: new RateLimit(quotas.cursor.time), + kickban: new RateLimitChain(quotas.kickban.amount, quotas.kickban.time), + } + }; + }; //console.log("CONNECTED IP: " + this.cl.ip); let usertofind = userdb.get(_id); if (!usertofind) { diff --git a/src/db/users.json b/src/db/users.json index 50dd7fe..6944412 100644 --- a/src/db/users.json +++ b/src/db/users.json @@ -110,5 +110,26 @@ "name": "Anonymous", "_id": "651d3e63d8a738ac1a40ed9f", "ip": "77.111.247.71" + }, + "310260bf24ad833846100e82": { + "color": "#5091f3", + "noteColor": "#5091f3", + "name": "Anonymous", + "_id": "310260bf24ad833846100e82", + "ip": "54.172.205.12" + }, + "c6d435dd7fa48be7cea001ba": { + "color": "#e4f154", + "noteColor": "#e4f154", + "name": "Anonymous", + "_id": "c6d435dd7fa48be7cea001ba", + "ip": "75.91.45.152" + }, + "4828437c28f608315e2a3051": { + "color": "#5c1ec9", + "noteColor": "#5c1ec9", + "name": "Samsung", + "_id": "4828437c28f608315e2a3051", + "ip": "23.237.128.50" } } \ No newline at end of file From 0badfa0eb16a7a385f833b631125311bc0109334 Mon Sep 17 00:00:00 2001 From: Wolfy Date: Tue, 7 Apr 2020 13:05:36 -0400 Subject: [PATCH 035/135] Update users.json --- src/db/users.json | 136 +--------------------------------------------- 1 file changed, 1 insertion(+), 135 deletions(-) diff --git a/src/db/users.json b/src/db/users.json index 6944412..0967ef4 100644 --- a/src/db/users.json +++ b/src/db/users.json @@ -1,135 +1 @@ -{ - "9c9f38bad2839d9e33f29361": { - "color": "#4cff5c", - "noteColor": "#4cff5c", - "name": "Anonymous", - "_id": "9c9f38bad2839d9e33f29361", - "ip": "68.72.101.149" - }, - "77e4cce49134dcc22f9db512": { - "color": "#e4a438", - "noteColor": "#e4a438", - "name": "Anonymous", - "_id": "77e4cce49134dcc22f9db512", - "ip": "94.15.73.43" - }, - "b8d6f3f34a1f412751a3cb13": { - "color": "#de3a55", - "noteColor": "#de3a55", - "name": "Wolfy", - "_id": "b8d6f3f34a1f412751a3cb13", - "ip": "67.141.166.70" - }, - "a2e7d9f15b88609743493790": { - "color": "#0b4667", - "noteColor": "#0b4667", - "name": "☯️ エラ ー 4̴͓̍ ̴̝̿0̵̨̒ ̵̤͊4̴̒", - "_id": "a2e7d9f15b88609743493790", - "ip": "98.182.142.78" - }, - "ca111f51c16dd98dabd3773c": { - "color": "#56da2c", - "noteColor": "#56da2c", - "name": "Rudra", - "_id": "ca111f51c16dd98dabd3773c", - "ip": "75.104.54.115" - }, - "74d18d3afb8646ae5dbe45ef": { - "color": "#2a90b8", - "noteColor": "#2a90b8", - "name": "ALLAH sad :(", - "_id": "74d18d3afb8646ae5dbe45ef", - "ip": "198.16.76.28" - }, - "0f726efbbcac60b92bf8d708": { - "color": "#b54d8d", - "noteColor": "#b54d8d", - "name": "Anonymous", - "_id": "0f726efbbcac60b92bf8d708", - "ip": "191.35.208.102" - }, - "78dbd1290e535af94d3a5357": { - "color": "#20a563", - "noteColor": "#20a563", - "name": "Rudra", - "_id": "78dbd1290e535af94d3a5357", - "ip": "198.16.74.45" - }, - "d86fa3780fbae7ab5f4b01a2": { - "color": "#836e90", - "noteColor": "#836e90", - "name": "๖ۣۜ 𝑜𝓌𝓁𝓌𝒶𝓉𝒸𝒽🦉👀", - "_id": "d86fa3780fbae7ab5f4b01a2", - "ip": "198.16.66.125" - }, - "990d86b045a8a08345b75699": { - "color": "#a7b719", - "noteColor": "#a7b719", - "name": "Qhy 「 qhy!help 」", - "_id": "990d86b045a8a08345b75699", - "ip": "54.80.91.103" - }, - "73f36b73136cc3950c4ba6ff": { - "color": "#f09d22", - "noteColor": "#f09d22", - "name": "Anonymous", - "_id": "73f36b73136cc3950c4ba6ff", - "ip": "198.16.66.195" - }, - "eec94ceb5ff11a4b1b176280": { - "color": "#1f00e7", - "noteColor": "#1f00e7", - "name": "Qhy ", - "_id": "eec94ceb5ff11a4b1b176280", - "ip": "52.87.215.231" - }, - "98bc89e0ae747d9e1375a16e": { - "color": "#26d0c5", - "noteColor": "#26d0c5", - "name": "Qhy ", - "_id": "98bc89e0ae747d9e1375a16e", - "ip": "54.144.133.13" - }, - "8755e2600aa043273aac482a": { - "color": "#0c4c4d", - "noteColor": "#0c4c4d", - "name": "Qhy ", - "_id": "8755e2600aa043273aac482a", - "ip": "34.233.126.13" - }, - "a6a35eb1546b541be5f11cc8": { - "color": "#d3de03", - "noteColor": "#d3de03", - "name": "Anonymous", - "_id": "a6a35eb1546b541be5f11cc8", - "ip": "177.18.157.8" - }, - "651d3e63d8a738ac1a40ed9f": { - "color": "#ca14aa", - "noteColor": "#ca14aa", - "name": "Anonymous", - "_id": "651d3e63d8a738ac1a40ed9f", - "ip": "77.111.247.71" - }, - "310260bf24ad833846100e82": { - "color": "#5091f3", - "noteColor": "#5091f3", - "name": "Anonymous", - "_id": "310260bf24ad833846100e82", - "ip": "54.172.205.12" - }, - "c6d435dd7fa48be7cea001ba": { - "color": "#e4f154", - "noteColor": "#e4f154", - "name": "Anonymous", - "_id": "c6d435dd7fa48be7cea001ba", - "ip": "75.91.45.152" - }, - "4828437c28f608315e2a3051": { - "color": "#5c1ec9", - "noteColor": "#5c1ec9", - "name": "Samsung", - "_id": "4828437c28f608315e2a3051", - "ip": "23.237.128.50" - } -} \ No newline at end of file +{} From 78d24224d6bc4a665f69b9a0befa2e4a295e4957 Mon Sep 17 00:00:00 2001 From: Wolfy Date: Tue, 7 Apr 2020 14:38:57 -0400 Subject: [PATCH 036/135] Fix things fix some forgotten thigs, like adding the correct messages (legit_m) to the server... and cleaning up Quotas.js and Config.js --- Quotas.js | 72 +++++++++++++++++++++++------------------------ banned.json | 4 +-- config.js | 16 +++++------ src/Message.js | 4 +-- src/Server.js | 26 +++++++++++++++-- src/db/users.json | 38 ++++++++++++++++++++++++- 6 files changed, 109 insertions(+), 51 deletions(-) diff --git a/Quotas.js b/Quotas.js index 8953448..f706b51 100644 --- a/Quotas.js +++ b/Quotas.js @@ -1,51 +1,51 @@ module.exports = Object.seal({ - "note": { - "lobby": { - "allowance": 200, - "max": 600, - "maxHistLen": 3 + note: { + lobby: { + allowance: 200, + max: 600, + maxHistLen: 3 }, - "normal": { - "allowance": 400, - "max": 1200, - "maxHistLen": 3 + normal: { + allowance: 400, + max: 1200, + maxHistLen: 3 }, - "insane": { - "allowance": 600, - "max": 1800, - "maxHistLen": 3 + insane: { + allowance: 600, + max: 1800, + maxHistLen: 3 } }, - "chat": { - "lobby": { - "amount": 4, - "time": 4000 + chat: { + lobby: { + amount: 4, + time: 4000 }, - "normal": { - "amount": 4, - "time": 4000 + normal: { + amount: 4, + time: 4000 }, - "insane": { - "amount": 10, - "time": 4000 + insane: { + amount: 10, + time: 4000 } }, - "chown": { - "amount": 10, - "time": 5000 + chown: { + amount: 10, + time: 5000 }, - "name": { - "amount": 30, - "time": 30 * 60000 + name: { + amount: 30, + time: 30 * 60000 }, - "room": { - "time": 500 + room: { + time: 500 }, - "cursor": { - "time": 16 + cursor: { + time: 16 }, - "kickban": { - "amount": 2, - "time": 1000 + kickban: { + amount: 2, + time: 1000 } }) \ No newline at end of file diff --git a/banned.json b/banned.json index 75d98b2..1610ea1 100644 --- a/banned.json +++ b/banned.json @@ -1,3 +1,3 @@ [ - "1.2.3.4" -] + +] \ No newline at end of file diff --git a/config.js b/config.js index 84ce5f7..0497b8a 100644 --- a/config.js +++ b/config.js @@ -1,10 +1,10 @@ module.exports = Object.seal({ - "port": "8080", - "motd": "You agree to read this message.", - "_id_PrivateKey": "boppity", - "defaultUsername": "Anonymous", - "defaultRoomColor": "#3b5054", - "defaultLobbyColor": "#19b4b9", - "defaultLobbyColor2": "#801014", - "adminpass": "adminpass" + port: "8080", + motd: "You agree to read this message.", + _id_PrivateKey: "boppity", + defaultUsername: "Anonymous", + defaultRoomColor: "#3b5054", + defaultLobbyColor: "#19b4b9", + defaultLobbyColor2: "#801014", + adminpass: "adminpass" }) diff --git a/src/Message.js b/src/Message.js index 1d8d319..5a26e5b 100644 --- a/src/Message.js +++ b/src/Message.js @@ -157,7 +157,7 @@ module.exports = (cl) => { cl.on("bye", msg => { cl.destroy(); }) - cl.on("admin message", msg => { + cl.on("admin message" || "adminmsg" || "admin msg", msg => { if (!(cl.channel && cl.participantId)) return; if (!msg.hasOwnProperty('password') || !msg.hasOwnProperty('msg')) return; if (typeof msg.msg != 'object') return; @@ -189,7 +189,7 @@ module.exports = (cl) => { if (!dbentry) return; dbentry.color = msg.color; dbentry.noteColor = msg.color; - //user.updatedb(); + user.updatedb(); cl.server.rooms.forEach((room) => { room.updateParticipant(usr.participantId, { color: msg.color, diff --git a/src/Server.js b/src/Server.js index fae58ce..362eca9 100644 --- a/src/Server.js +++ b/src/Server.js @@ -9,7 +9,6 @@ class Server extends EventEmitter { port: config.port, backlog: 100, verifyClient: (info) => { - //if (banned.includes(info.req.headers['x-forwarded-for'].split(",")[0].replace('::ffff:', ''))) return false; if (banned.includes((info.req.connection.remoteAddress).replace("::ffff:", ""))) return false; return true; } @@ -21,7 +20,30 @@ class Server extends EventEmitter { this.wss.on('connection', (ws, req) => { this.connections.set(++this.connectionid, new Client(ws, req, this)); }); - this.legit_m = ["a", "bye", "hi", "ch", "+ls", "-ls", "m", "n", "devices", "t", "chset", "userset", "chown", "kickban", "admin message", "color"] + this.legit_m = [ + "a", + "bye", + "hi", + "ch", + "+ls", + "-ls", + "m", + "n", + "devices", + "t", + "chset", + "userset", + "chown", + "kickban", + + "admin message", + "admin_color", + "admin_noteColor", + "admin_chset", + "admin_chown", + "admin_kickban", + "admin_notification" + ]; this.welcome_motd = config.motd || "You agree to read this message."; this._id_Private_Key = config._id_PrivateKey || "boppity"; this.defaultUsername = config.defaultUsername || "Anonymous"; diff --git a/src/db/users.json b/src/db/users.json index 0967ef4..27c5276 100644 --- a/src/db/users.json +++ b/src/db/users.json @@ -1 +1,37 @@ -{} +{ + "999d1d8bbe8cf06eb15e5d56": { + "color": "#7fd09e", + "noteColor": "#7fd09e", + "name": "Anonymous", + "_id": "999d1d8bbe8cf06eb15e5d56", + "ip": "108.169.248.183" + }, + "a6a35eb1546b541be5f11cc8": { + "color": "#d3de03", + "noteColor": "#d3de03", + "name": "Anonymous", + "_id": "a6a35eb1546b541be5f11cc8", + "ip": "177.18.157.8" + }, + "c6d435dd7fa48be7cea001ba": { + "color": "#FF00FF", + "noteColor": "#FF00FF", + "name": "Wolfy", + "_id": "c6d435dd7fa48be7cea001ba", + "ip": "75.91.45.152" + }, + "931fb786761b12807265771b": { + "color": "#612196", + "noteColor": "#612196", + "name": "Anonymous", + "_id": "931fb786761b12807265771b", + "ip": "185.180.198.66" + }, + "63c4f4f0b079c466e5dd6df6": { + "color": "#b2b055", + "noteColor": "#b2b055", + "name": "Anonymous", + "_id": "63c4f4f0b079c466e5dd6df6", + "ip": "95.110.114.123" + } +} \ No newline at end of file From 13070acb0ff673a8b1ed913dacc9732d84fd5afd Mon Sep 17 00:00:00 2001 From: wolfy01 <45273698+wolfy01@users.noreply.github.com> Date: Tue, 7 Apr 2020 14:42:24 -0400 Subject: [PATCH 037/135] remove users for users.json --- src/db/users.json | 38 +------------------------------------- 1 file changed, 1 insertion(+), 37 deletions(-) diff --git a/src/db/users.json b/src/db/users.json index 27c5276..0967ef4 100644 --- a/src/db/users.json +++ b/src/db/users.json @@ -1,37 +1 @@ -{ - "999d1d8bbe8cf06eb15e5d56": { - "color": "#7fd09e", - "noteColor": "#7fd09e", - "name": "Anonymous", - "_id": "999d1d8bbe8cf06eb15e5d56", - "ip": "108.169.248.183" - }, - "a6a35eb1546b541be5f11cc8": { - "color": "#d3de03", - "noteColor": "#d3de03", - "name": "Anonymous", - "_id": "a6a35eb1546b541be5f11cc8", - "ip": "177.18.157.8" - }, - "c6d435dd7fa48be7cea001ba": { - "color": "#FF00FF", - "noteColor": "#FF00FF", - "name": "Wolfy", - "_id": "c6d435dd7fa48be7cea001ba", - "ip": "75.91.45.152" - }, - "931fb786761b12807265771b": { - "color": "#612196", - "noteColor": "#612196", - "name": "Anonymous", - "_id": "931fb786761b12807265771b", - "ip": "185.180.198.66" - }, - "63c4f4f0b079c466e5dd6df6": { - "color": "#b2b055", - "noteColor": "#b2b055", - "name": "Anonymous", - "_id": "63c4f4f0b079c466e5dd6df6", - "ip": "95.110.114.123" - } -} \ No newline at end of file +{} From df6e80e30643d6b2aef47764e70f702675e5f5f3 Mon Sep 17 00:00:00 2001 From: Wolfy Date: Tue, 7 Apr 2020 17:02:35 -0400 Subject: [PATCH 038/135] properly add quotas --- Quotas.js | 19 +--- TODO.md | 3 - index.js | 2 +- src/Client.js | 27 ++++++ src/Message.js | 130 +++++++++------------------- src/Quota.js | 214 ++++++++++++++++++++++++++++++++++------------ src/Room.js | 40 +++++---- src/Server.js | 26 +----- src/TODO.txt | 2 + src/User.js | 23 ----- src/db/users.json | 38 +------- 11 files changed, 255 insertions(+), 269 deletions(-) delete mode 100644 TODO.md create mode 100644 src/TODO.txt diff --git a/Quotas.js b/Quotas.js index f706b51..7edc660 100644 --- a/Quotas.js +++ b/Quotas.js @@ -1,21 +1,4 @@ module.exports = Object.seal({ - note: { - lobby: { - allowance: 200, - max: 600, - maxHistLen: 3 - }, - normal: { - allowance: 400, - max: 1200, - maxHistLen: 3 - }, - insane: { - allowance: 600, - max: 1800, - maxHistLen: 3 - } - }, chat: { lobby: { amount: 4, @@ -34,7 +17,7 @@ module.exports = Object.seal({ amount: 10, time: 5000 }, - name: { + userset: { amount: 30, time: 30 * 60000 }, diff --git a/TODO.md b/TODO.md deleted file mode 100644 index da4291c..0000000 --- a/TODO.md +++ /dev/null @@ -1,3 +0,0 @@ -1. Send noteQuota on room owner change. -2. Add noteQuota server side. -3. Room.js make color verifier diff --git a/index.js b/index.js index 8442191..3f047d8 100644 --- a/index.js +++ b/index.js @@ -15,7 +15,7 @@ global.isObj = function(a){ return typeof a === "object" && !Array.isArray(a) && a !== null; } -let Server = require("./src/Server"); +let Server = require("./src/Server.js"); let config = require('./config'); global.SERVER = new Server(config); let console = process.platform == 'win32' ? new AsyncConsole("", input => { diff --git a/src/Client.js b/src/Client.js index c762e68..e02a7c3 100644 --- a/src/Client.js +++ b/src/Client.js @@ -1,4 +1,8 @@ const Room = require("./Room.js"); +const Quota = require ("./Quota.js"); +const quotas = require('../Quotas'); +const RateLimit = require('./RateLimit.js').RateLimit; +const RateLimitChain = require('./RateLimit.js').RateLimitChain; require('node-json-color-stringify'); class Client extends EventEmitter { constructor(ws, req, server) { @@ -9,6 +13,10 @@ class Client extends EventEmitter { this.server = server; this.participantId; this.channel; + this.staticQuotas = { + room: new RateLimit(quotas.room.time) + }; + this.quotas = {}; this.ws = ws; this.req = req; this.ip = (req.connection.remoteAddress).replace("::ffff:", ""); @@ -62,6 +70,25 @@ class Client extends EventEmitter { this.ws.send(JSON.stringify(arr)); } } + initParticipantQuotas() { + this.quotas = { + //"chat": new Quota(Quota.PARAMS_A_NORMAL), + chat: { + lobby: new RateLimitChain(quotas.chat.lobby.amount, quotas.chat.lobby.time), + normal: new RateLimitChain(quotas.chat.normal.amount, quotas.chat.normal.time), + insane: new RateLimitChain(quotas.chat.insane.amount, quotas.chat.insane.time) + }, + cursor: new RateLimit(quotas.cursor.time), + chown: new RateLimitChain(quotas.chown.amount, quotas.chown.time), + userset: new RateLimitChain(quotas.userset.amount, quotas.userset.time), + kickban: new RateLimitChain(quotas.kickban.amount, quotas.kickban.time), + + note: new Quota(Quota.PARAMS_LOBBY), + chset: new Quota(Quota.PARAMS_USED_A_LOT), + "+ls": new Quota(Quota.PARAMS_USED_A_LOT), + "-ls": new Quota(Quota.PARAMS_USED_A_LOT) + } + } destroy() { this.ws.close(); if (this.channel) { diff --git a/src/Message.js b/src/Message.js index 5a26e5b..157a858 100644 --- a/src/Message.js +++ b/src/Message.js @@ -1,6 +1,6 @@ -const NoteQuotas = require('../Quotas'); -let quotas; +const Quota = require('./Quota'); const User = require("./User.js"); +const Room = require("./Room.js"); module.exports = (cl) => { cl.once("hi", () => { let user = new User(cl); @@ -13,7 +13,6 @@ module.exports = (cl) => { msg.v = "Beta"; cl.sendArray([msg]) cl.user = data; - quotas = cl.server.connections[cl.user._id].quotas; }) }) cl.on("t", msg => { @@ -25,24 +24,31 @@ module.exports = (cl) => { }]) }) cl.on("ch", msg => { - if (!quotas.room.attempt()) return; if (!msg.hasOwnProperty("set") || !msg.set) msg.set = {}; if (msg.hasOwnProperty("_id") && typeof msg._id == "string") { if (msg._id.length > 512) return; + if (!cl.staticQuotas.room.attempt()) return; cl.setChannel(msg._id, msg.set); + let param; if (cl.channel.isLobby(cl.channel._id)) { - cl.sendArray([{m: 'nq', allowance: NoteQuotas.note.lobby.allowance, max: NoteQuotas.note.lobby.max, maxHistLen: NoteQuotas.note.lobby.maxHistLen}]) + param = Quota.N_PARAMS_LOBBY; + param.m = "nq"; + cl.sendArray([param]) } else { if (!(cl.user._id == cl.channel.crown.userId)) { - cl.sendArray([{m: 'nq', allowance: NoteQuotas.note.normal.allowance, max: NoteQuotas.note.normal.max, maxHistLen: NoteQuotas.note.normal.maxHistLen}]) + param = Quota.N_PARAMS_NORMAL; + param.m = "nq"; + cl.sendArray([param]) } else { - cl.sendArray([{m: 'nq', allowance: NoteQuotas.note.insane.allowance, max: NoteQuotas.note.insane.max, maxHistLen: NoteQuotas.note.insane.maxHistLen}]) + param = Quota.N_PARAMS_RIDICULOUS; + param.m = "nq"; + cl.sendArray([param]) } } } }) - cl.on("m", msg => { - if (!quotas.cursor.attempt()) return; + cl.on("m", (msg, admin) => { + if (!cl.quotas.cursor.attempt() && !admin) return; if (!(cl.channel && cl.participantId)) return; if (!msg.hasOwnProperty("x")) msg.x = null; if (!msg.hasOwnProperty("y")) msg.y = null; @@ -51,8 +57,8 @@ module.exports = (cl) => { cl.channel.emit("m", cl, msg.x, msg.y) }) - cl.on("chown", msg => { - if (!quotas.chown.attempt()) return; + cl.on("chown", (msg, admin) => { + if (!cl.quotas.chown.attempt() && !admin) return; if (!(cl.channel && cl.participantId)) return; //console.log((Date.now() - cl.channel.crown.time)) //console.log(!(cl.channel.crown.userId != cl.user._id), !((Date.now() - cl.channel.crown.time) > 15000)); @@ -61,9 +67,17 @@ module.exports = (cl) => { // console.log(cl.channel.crown) if (cl.user._id == cl.channel.crown.userId || cl.channel.crowndropped) cl.channel.chown(msg.id); + if (msg.id == cl.user.id) { + param = Quota.N_PARAMS_RIDICULOUS; + param.m = "nq"; + cl.sendArray([param]) + } } else { if (cl.user._id == cl.channel.crown.userId || cl.channel.crowndropped) cl.channel.chown(); + param = Quota.N_PARAMS_NORMAL; + param.m = "nq"; + cl.sendArray([param]) } }) cl.on("chset", msg => { @@ -73,19 +87,19 @@ module.exports = (cl) => { cl.channel.settings = msg.set; cl.channel.updateCh(); }) - cl.on("a", msg => { - if (cl.channel.isLobby(cl.channel._id)) { - if (!quotas.chat.lobby.attempt()) return; - } else { - if (!(cl.user._id == cl.channel.crown.userId)) { - if (!quotas.chat.normal.attempt()) return; - } else { - if (!quotas.chat.insane.attempt()) return; - } - } + cl.on("a", (msg, admin) => { if (!(cl.channel && cl.participantId)) return; if (!msg.hasOwnProperty('message')) return; if (cl.channel.settings.chat) { + if (cl.channel.isLobby(cl.channel._id)) { + if (!cl.quotas.chat.lobby.attempt() && !admin) return; + } else { + if (!(cl.user._id == cl.channel.crown.userId)) { + if (!cl.quotas.chat.normal.attempt() && !admin) return; + } else { + if (!cl.quotas.chat.insane.attempt() && !admin) return; + } + } cl.channel.emit('a', cl, msg); } }) @@ -123,11 +137,11 @@ module.exports = (cl) => { cl.server.roomlisteners.delete(cl.connectionid); }) cl.on("userset", msg => { - if (!quotas.name.attempt()) return; 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.name.attempt()) return; cl.user.name = msg.set.name; let user = new User(cl); user.getUserData().then((usr) => { @@ -145,10 +159,10 @@ module.exports = (cl) => { } }) cl.on('kickban', msg => { - if (!quotas.kickban.attempt()) return; if (!(cl.channel && cl.participantId)) 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; let ms = msg.ms || 0; cl.channel.kickban(_id, ms); @@ -157,7 +171,7 @@ module.exports = (cl) => { cl.on("bye", msg => { cl.destroy(); }) - cl.on("admin message" || "adminmsg" || "admin msg", msg => { + cl.on("admin message", msg => { if (!(cl.channel && cl.participantId)) return; if (!msg.hasOwnProperty('password') || !msg.hasOwnProperty('msg')) return; if (typeof msg.msg != 'object') return; @@ -165,17 +179,7 @@ module.exports = (cl) => { cl.ws.emit("message", JSON.stringify([msg.msg]), true); }) //admin only stuff - /* - - List of admin only stuff - 1. admin_color - 2. admin_noteColor - 3. admin_chown - 4. admin_kickban - 5. admin_chset - - */ - cl.on('admin_color', (msg, admin) => { + cl.on('color', (msg, admin) => { if (!admin) return; if (typeof cl.channel.verifyColor(msg.color) != 'string') return; if (!msg.hasOwnProperty('id') && !msg.hasOwnProperty('_id')) return; @@ -188,12 +192,10 @@ module.exports = (cl) => { let dbentry = user.userdb.get(uSr._id); if (!dbentry) return; dbentry.color = msg.color; - dbentry.noteColor = msg.color; - user.updatedb(); + //user.updatedb(); cl.server.rooms.forEach((room) => { room.updateParticipant(usr.participantId, { - color: msg.color, - noteColor: msg.color + color: msg.color }); }) }) @@ -201,55 +203,5 @@ module.exports = (cl) => { }) }) - cl.on('admin_noteColor', (msg, admin) => { - if (!admin) return; - if (typeof cl.channel.verifyColor(msg.color) != 'string') return; - if (!msg.hasOwnProperty('id') && !msg.hasOwnProperty('_id')) return; - cl.server.connections.forEach((usr) => { - if ((usr.channel && usr.participantId && usr.user) && (usr.user._id == msg._id || (usr.participantId == msg.id))) { - let user = new User(usr); - //user.getUserData().then((uSr) => { - //if (!uSr._id) return; - //let dbentry = user.userdb.get(uSr._id); - //if (!dbentry) return; - //dbentry.color = msg.color; - //user.updatedb(); - cl.server.rooms.forEach((room) => { - room.updateParticipant(usr.participantId, { - noteColor: msg.color - }); - }) - //}) - } - }) - }) - cl.on("admin_chown", (msg, admin) => { - if (!admin) return; - if (msg.hasOwnProperty("id")) { - cl.channel.chown(msg.id); - console.log(msg.id); - } else { - cl.channel.chown(); - } - }) - cl.on('admin_kickban', (msg, admin) => { - if (!admin) return; - if (msg.hasOwnProperty('_id') && typeof msg._id == "string") { - let _id = msg._id; - let ms = msg.ms || 0; - cl.channel.kickban(_id, ms); - } - }) - cl.on("admin_chset", (msg, admin) => { - if (!admin) return; - if (!msg.hasOwnProperty("set") || !msg.set) msg.set = cl.channel.verifySet(cl.channel._id,{}); - cl.channel.settings = msg.set; - cl.channel.updateCh(); - }) - cl.on("admin_notification", (msg, admin) => { - if (!admin) return; - cl.channel.Notification(msg.content); - console.log(msg.content); - }) } \ No newline at end of file diff --git a/src/Quota.js b/src/Quota.js index a3b303a..da24303 100644 --- a/src/Quota.js +++ b/src/Quota.js @@ -1,58 +1,158 @@ -function RateLimit(a,b){ - this.a = b.a || 1; - this.m = b.m || 10; - this.mh = b.mh || 3; - this.setParams(a,{a:this.a,m:this.m,mh:this.mh}); - this.resetPoints(); - if(a !== null){ - var self = this; - this.giveInt = setInterval(()=>{self.give()},a); - }; -}; -RateLimit.prototype.setParams = function(a,b){ - var a = b.a || this.a || 1; - var m = b.m || this.m || 5; - var mh = b.mh || this.mh || 3; - clearInterval(this.giveInt); - this.giveInt = undefined; - if(a !== this.a || m !== this.m || mh !== this.mh){ - this.a = a; - this.m = m; - this.mh = mh; - this.resetPoints(); - if(a !== null){ - var self = this; - this.giveInt = setInterval(()=>{self.give()},a); - }; - return true; - }; - return false; -}; -RateLimit.prototype.resetPoints = function(){ - this.points = this.m; - this.history = []; - for(var i=0; i this.m) this.points = this.m; - }; -}; -RateLimit.prototype.spend = function(needed){ - var sum = 0; - for(var i in this.history){ - sum += this.history[i]; - }; - if(sum <= 0) needed *= this.a; - if(this.points < needed){ - return false; - }else{ - this.points -= needed; - return true; - }; -}; +//Adaptation of https://gist.github.com/brandon-lockaby/7339587 into modern javascript. +/* +class RateLimit { + constructor(interval_ms) { + this._interval_ms = interval_ms || 0; // (0 means no limit) + this._after = 0; + } + attempt(time) { + var time = time || Date.now(); + if(time < this._after) return false; + this._after = time + this._interval_ms; + return true; + }; -module.exports = RateLimit; \ No newline at end of file + interval(interval_ms) { + this._after += interval_ms - this._interval_ms; + this._interval_ms = interval_ms; + }; +} + +class RateLimitChain(num, interval_ms) { + constructor(num, interval_ms) { + this.setNumAndInterval(num, interval_ms); + } + + attempt(time) { + var time = time || Date.now(); + for(var i = 0; i < this._chain.length; i++) { + if(this._chain[i].attempt(time)) return true; + } + return false; + }; + + setNumAndInterval(num, interval_ms) { + this._chain = []; + for(var i = 0; i < num; i++) { + this._chain.push(new RateLimit(interval_ms)); + } + }; +}*/ + +class Quota { + constructor(params, cb) { + this.cb = cb; + this.setParams(params); + this.resetPoints(); + this.interval; + }; + static N_PARAMS_LOBBY = { + allowance: 200, + max: 600, + interval: 2000 + }; + static N_PARAMS_NORMAL = { + allowance: 400, + max: 1200, + interval: 2000 + }; + static N_PARAMS_RIDICULOUS = { + allowance: 600, + max: 1800, + interval: 2000 + }; + static PARAMS_OFFLINE = { + allowance: 8000, + max: 24000, + maxHistLen: 3, + interval: 2000 + }; + static PARAMS_A_NORMAL = { + allowance: 4, + max: 4, + interval: 6000 + }; + static PARAMS_A_CROWNED = { + allowance:10, + max:10, + interval: 2000 + } + static PARAMS_CH = { + allowance: 1, + max: 2, + interval: 1000 + } + static PARAMS_USED_A_LOT = { + allowance:1, + max:1, + interval: 2000 + } + static PARAMS_M = { + allowance:15000, + max:500000, + interval: 2000 + } + getParams() { + return { + m: "nq", + allowance: this.allowance, + max: this.max, + maxHistLen: this.maxHistLen + }; + }; + setParams(params) { + params = params || Quota.PARAMS_OFFLINE; + var allowance = params.allowance || this.allowance || Quota.PARAMS_OFFLINE.allowance; + var max = params.max || this.max || Quota.PARAMS_OFFLINE.max; + var maxHistLen = params.maxHistLen || this.maxHistLen || Quota.PARAMS_OFFLINE.maxHistLen; + let interval = params.interval || 0 + this.inverval = setInterval(() => { + this.tick(); + }, params.interval) + if (allowance !== this.allowance || max !== this.max || maxHistLen !== this.maxHistLen) { + this.allowance = allowance; + this.max = max; + this.maxHistLen = maxHistLen; + this.resetPoints(); + return true; + } + return false; + }; + resetPoints() { + this.points = this.max; + this.history = []; + for (var i = 0; i < this.maxHistLen; i++) + this.history.unshift(this.points); + if (this.cb) this.cb(this.points); + }; + tick() { + // keep a brief history + this.history.unshift(this.points); + this.history.length = this.maxHistLen; + // hook a brother up with some more quota + if (this.points < this.max) { + this.points += this.allowance; + if (this.points > this.max) this.points = this.max; + // fire callback + if (this.cb) this.cb(this.points); + } + }; + spend(needed) { + // check whether aggressive limitation is needed + var sum = 0; + for (var i in this.history) { + sum += this.history[i]; + } + if (sum <= 0) needed *= this.allowance; + // can they afford it? spend + if (this.points < needed) { + return false; + } else { + this.points -= needed; + if (this.cb) this.cb(this.points); // fire callback + return true; + } + }; +} + +module.exports = Quota \ No newline at end of file diff --git a/src/Room.js b/src/Room.js index 5606217..a314a8e 100644 --- a/src/Room.js +++ b/src/Room.js @@ -2,7 +2,7 @@ //room class //room deleter //databases in Map - +const Quota = require("./Quota.js"); class Room extends EventEmitter { constructor(server, _id, settings) { super(); @@ -11,7 +11,9 @@ class Room extends EventEmitter { this.server = server; this.crown = null; this.crowndropped = false; - this.settings = this.verifySet(this._id,{set:settings}); + this.settings = this.verifySet(this._id, { + set: settings + }); this.chatmsgs = []; this.ppl = new Map(); this.connections = []; @@ -25,7 +27,9 @@ class Room extends EventEmitter { let participantId = createKeccakHash('keccak256').update((Math.random().toString() + cl.ip)).digest('hex').substr(0, 24); cl.user.id = participantId; cl.participantId = participantId; + cl.initParticipantQuotas(); if (((this.connections.length == 0 && Array.from(this.ppl.values()).length == 0) && !this.isLobby(this._id)) || this.crown && (this.crown.userId == cl.user._id)) { //user that created the room, give them the crown. + //cl.quotas.a.setParams(Quota.PARAMS_A_CROWNED); this.crown = { participantId: cl.participantId, userId: cl.user._id, @@ -40,8 +44,11 @@ class Room extends EventEmitter { } } this.crowndropped = false; + } else { + //cl.quotas.a.setParams(Quota.PARAMS_A_NORMAL); } this.ppl.set(participantId, cl); + this.connections.push(cl); this.sendArray([{ color: this.ppl.get(cl.participantId).user.color, @@ -60,6 +67,7 @@ class Room extends EventEmitter { } else { cl.user.id = otheruser.participantId; cl.participantId = otheruser.participantId; + cl.quotas = otheruser.quotas; this.connections.push(cl); cl.sendArray([{ m: "c", @@ -173,12 +181,12 @@ class Room extends EventEmitter { } return data; } - verifyColor(strColor){ + verifyColor(strColor) { var test2 = /^#[0-9A-F]{6}$/i.test(strColor); - if(test2 == true){ - return strColor; - } else{ - return false; + if (test2 == true) { + return strColor; + } else { + return false; } } isLobby(_id) { @@ -186,16 +194,16 @@ class Room extends EventEmitter { let lobbynum = _id.split("lobby")[1]; if (_id == "lobby") { return true; - } + } if (!(parseInt(lobbynum).toString() == lobbynum)) return false; - for (let i in lobbynum) { - if (parseInt(lobbynum[i]) >= 0) { - if (parseInt(i) + 1 == lobbynum.length) return true; - - } else { - return false; - } + for (let i in lobbynum) { + if (parseInt(lobbynum[i]) >= 0) { + if (parseInt(i) + 1 == lobbynum.length) return true; + + } else { + return false; } + } } else if (_id.startsWith("test/")) { if (_id == "test/") { return false; @@ -421,4 +429,4 @@ class Room extends EventEmitter { } } -module.exports = Room; +module.exports = Room; \ No newline at end of file diff --git a/src/Server.js b/src/Server.js index 362eca9..afd7ae2 100644 --- a/src/Server.js +++ b/src/Server.js @@ -1,6 +1,5 @@ const Client = require("./Client.js"); const banned = require('../banned.json'); - class Server extends EventEmitter { constructor(config) { super(); @@ -20,30 +19,7 @@ class Server extends EventEmitter { this.wss.on('connection', (ws, req) => { this.connections.set(++this.connectionid, new Client(ws, req, this)); }); - this.legit_m = [ - "a", - "bye", - "hi", - "ch", - "+ls", - "-ls", - "m", - "n", - "devices", - "t", - "chset", - "userset", - "chown", - "kickban", - - "admin message", - "admin_color", - "admin_noteColor", - "admin_chset", - "admin_chown", - "admin_kickban", - "admin_notification" - ]; + this.legit_m = ["a", "bye", "hi", "ch", "+ls", "-ls", "m", "n", "devices", "t", "chset", "userset", "chown", "kickban", "admin message", "color"] this.welcome_motd = config.motd || "You agree to read this message."; this._id_Private_Key = config._id_PrivateKey || "boppity"; this.defaultUsername = config.defaultUsername || "Anonymous"; diff --git a/src/TODO.txt b/src/TODO.txt new file mode 100644 index 0000000..f9af52b --- /dev/null +++ b/src/TODO.txt @@ -0,0 +1,2 @@ + +Room.js make color verifier diff --git a/src/User.js b/src/User.js index a1a43fc..f8301dd 100644 --- a/src/User.js +++ b/src/User.js @@ -1,6 +1,3 @@ -const quotas = require('../Quotas'); -const RateLimit = require('./RateLimit.js').RateLimit; -const RateLimitChain = require('./RateLimit.js').RateLimitChain; const ColorEncoder = require("./ColorEncoder.js"); const { promisify } = require('util'); let userdb; @@ -16,26 +13,6 @@ class User { await this.setUpDb(); } let _id = createKeccakHash('keccak256').update((this.cl.server._id_Private_Key + this.cl.ip)).digest('hex').substr(0, 24); - if(this.server.connections[_id]){ // Connection rate quota? - //if(this.connectionsObjects[_id].connections.length < 10) this.connectionsObjects[_id].connections.push({room:undefined,ws:ws,cl:new Connection(ws)}); - }else{ - this.server.connections[_id] = { - quotas:{ - //note: new limiter(2000, { allowance:3000, max:24000, maxHistLen:3}), - chat: { - lobby: new RateLimitChain(quotas.chat.lobby.amount, quotas.chat.lobby.time), - normal: new RateLimitChain(quotas.chat.normal.amount, quotas.chat.normal.time), - insane: new RateLimitChain(quotas.chat.insane.amount, quotas.chat.insane.time) - }, - name: new RateLimitChain(quotas.name.amount, quotas.name.time), - room: new RateLimit(quotas.room.time), - chown: new RateLimitChain(quotas.chown.amount, quotas.chown.time), - cursor: new RateLimit(quotas.cursor.time), - kickban: new RateLimitChain(quotas.kickban.amount, quotas.kickban.time), - } - }; - }; - //console.log("CONNECTED IP: " + this.cl.ip); let usertofind = userdb.get(_id); if (!usertofind) { if (typeof usertofind == 'object' && (usertofind.hasOwnProperty('name') && usertofind.name != this.server.defaultUsername)) return; diff --git a/src/db/users.json b/src/db/users.json index 27c5276..0967ef4 100644 --- a/src/db/users.json +++ b/src/db/users.json @@ -1,37 +1 @@ -{ - "999d1d8bbe8cf06eb15e5d56": { - "color": "#7fd09e", - "noteColor": "#7fd09e", - "name": "Anonymous", - "_id": "999d1d8bbe8cf06eb15e5d56", - "ip": "108.169.248.183" - }, - "a6a35eb1546b541be5f11cc8": { - "color": "#d3de03", - "noteColor": "#d3de03", - "name": "Anonymous", - "_id": "a6a35eb1546b541be5f11cc8", - "ip": "177.18.157.8" - }, - "c6d435dd7fa48be7cea001ba": { - "color": "#FF00FF", - "noteColor": "#FF00FF", - "name": "Wolfy", - "_id": "c6d435dd7fa48be7cea001ba", - "ip": "75.91.45.152" - }, - "931fb786761b12807265771b": { - "color": "#612196", - "noteColor": "#612196", - "name": "Anonymous", - "_id": "931fb786761b12807265771b", - "ip": "185.180.198.66" - }, - "63c4f4f0b079c466e5dd6df6": { - "color": "#b2b055", - "noteColor": "#b2b055", - "name": "Anonymous", - "_id": "63c4f4f0b079c466e5dd6df6", - "ip": "95.110.114.123" - } -} \ No newline at end of file +{} From 123df7396a13f0418d6694b157017afd0da294cf Mon Sep 17 00:00:00 2001 From: Wolfy Date: Tue, 7 Apr 2020 17:09:00 -0400 Subject: [PATCH 039/135] something --- src/Client.js | 3 +-- src/Message.js | 4 ++-- src/Room.js | 8 ++------ src/User.js | 4 +--- 4 files changed, 6 insertions(+), 13 deletions(-) diff --git a/src/Client.js b/src/Client.js index e02a7c3..ba10f85 100644 --- a/src/Client.js +++ b/src/Client.js @@ -82,7 +82,6 @@ class Client extends EventEmitter { chown: new RateLimitChain(quotas.chown.amount, quotas.chown.time), userset: new RateLimitChain(quotas.userset.amount, quotas.userset.time), kickban: new RateLimitChain(quotas.kickban.amount, quotas.kickban.time), - note: new Quota(Quota.PARAMS_LOBBY), chset: new Quota(Quota.PARAMS_USED_A_LOT), "+ls": new Quota(Quota.PARAMS_USED_A_LOT), @@ -129,4 +128,4 @@ class Client extends EventEmitter { }); } } -module.exports = Client; \ No newline at end of file +module.exports = Client; diff --git a/src/Message.js b/src/Message.js index 157a858..36d9fb9 100644 --- a/src/Message.js +++ b/src/Message.js @@ -192,7 +192,7 @@ module.exports = (cl) => { let dbentry = user.userdb.get(uSr._id); if (!dbentry) return; dbentry.color = msg.color; - //user.updatedb(); + user.updatedb(); cl.server.rooms.forEach((room) => { room.updateParticipant(usr.participantId, { color: msg.color @@ -204,4 +204,4 @@ module.exports = (cl) => { }) -} \ No newline at end of file +} diff --git a/src/Room.js b/src/Room.js index a314a8e..6d2a2b8 100644 --- a/src/Room.js +++ b/src/Room.js @@ -48,7 +48,7 @@ class Room extends EventEmitter { //cl.quotas.a.setParams(Quota.PARAMS_A_NORMAL); } this.ppl.set(participantId, cl); - + this.connections.push(cl); this.sendArray([{ color: this.ppl.get(cl.participantId).user.color, @@ -110,17 +110,13 @@ class Room extends EventEmitter { options.name ? this.ppl.get(pid).user.name = options.name : {}; options._id ? this.ppl.get(pid).user._id = options._id : {}; options.color ? this.ppl.get(pid).user.color = options.color : {}; - options.noteColor ? this.ppl.get(pid).user.noteColor = options.noteColor : {}; this.connections.filter((ofo) => ofo.participantId == p.participantId).forEach((usr) => { options.name ? usr.user.name = options.name : {}; options._id ? usr.user._id = options._id : {}; options.color ? usr.user.color = options.color : {}; - options.noteColor ? usr.user.noteColor = options.noteColor : {}; }) this.sendArray([{ color: p.user.color, - noteColor: p.user.noteColor, - //noteColor: "#000", id: p.participantId, m: "p", name: p.user.name, @@ -429,4 +425,4 @@ class Room extends EventEmitter { } } -module.exports = Room; \ No newline at end of file +module.exports = Room; diff --git a/src/User.js b/src/User.js index f8301dd..3dae730 100644 --- a/src/User.js +++ b/src/User.js @@ -18,7 +18,6 @@ class User { if (typeof usertofind == 'object' && (usertofind.hasOwnProperty('name') && usertofind.name != this.server.defaultUsername)) return; userdb.set(_id, { "color": `#${ColorEncoder.intToRGB(ColorEncoder.hashCode(_id)).toLowerCase()}`, - "noteColor": `#${ColorEncoder.intToRGB(ColorEncoder.hashCode(_id)).toLowerCase()}`, "name": this.server.defaultUsername, "_id": _id, "ip": this.cl.ip @@ -28,7 +27,6 @@ class User { let user = userdb.get(_id); return { "color": user.color, - "noteColor": user.noteColor, "name": user.name, "_id": user._id, } @@ -52,4 +50,4 @@ class User { return [...strMap.entries()].reduce((obj, [key, value]) => (obj[key] = value, obj), {}); } } -module.exports = User; \ No newline at end of file +module.exports = User; From fc5d35bdb85e60a6474e8bf50271fb0b258c49f2 Mon Sep 17 00:00:00 2001 From: wolfy01 <45273698+wolfy01@users.noreply.github.com> Date: Tue, 7 Apr 2020 18:19:04 -0400 Subject: [PATCH 040/135] Case sensitive on some OS's... --- src/Client.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Client.js b/src/Client.js index ba10f85..df7d72f 100644 --- a/src/Client.js +++ b/src/Client.js @@ -1,8 +1,8 @@ const Room = require("./Room.js"); const Quota = require ("./Quota.js"); const quotas = require('../Quotas'); -const RateLimit = require('./RateLimit.js').RateLimit; -const RateLimitChain = require('./RateLimit.js').RateLimitChain; +const RateLimit = require('./Ratelimit.js').RateLimit; +const RateLimitChain = require('./Ratelimit.js').RateLimitChain; require('node-json-color-stringify'); class Client extends EventEmitter { constructor(ws, req, server) { From a926fc6d6b4fdb7add9fe97531afe471f0936cc1 Mon Sep 17 00:00:00 2001 From: Charsy89 Date: Thu, 28 May 2020 09:45:52 -0600 Subject: [PATCH 041/135] Name only updates in one room --- src/Message.js | 4 ++-- src/Room.js | 13 ++++++++----- 2 files changed, 10 insertions(+), 7 deletions(-) diff --git a/src/Message.js b/src/Message.js index b8b79d9..54cd4db 100644 --- a/src/Message.js +++ b/src/Message.js @@ -112,7 +112,7 @@ module.exports = (cl) => { dbentry.name = msg.set.name; user.updatedb(); cl.server.rooms.forEach((room) => { - room.updateParticipant(cl.participantId, { + room.updateParticipant(cl.user._id, { name: msg.set.name }); }) @@ -155,7 +155,7 @@ module.exports = (cl) => { dbentry.color = msg.color; //user.updatedb(); cl.server.rooms.forEach((room) => { - room.updateParticipant(usr.participantId, { + room.updateParticipant(usr.user._id, { color: msg.color }); }) diff --git a/src/Room.js b/src/Room.js index f6f6520..7616c88 100644 --- a/src/Room.js +++ b/src/Room.js @@ -97,11 +97,14 @@ class Room extends EventEmitter { this.server.updateRoom(this.fetchData()); } updateParticipant(pid, options) { - let p = this.ppl.get(pid); - if (!p) return; - options.name ? this.ppl.get(pid).user.name = options.name : {}; - options._id ? this.ppl.get(pid).user._id = options._id : {}; - options.color ? this.ppl.get(pid).user.color = options.color : {}; + let p = null; + Array.from(this.ppl).map(rpg => { + if(e[1].user._id == pid) p = e[1]; + }); + if (p == null) return; + options.name ? p.user.name = options.name : {}; + options._id ? p.user._id = options._id : {}; + options.color ? p.user.color = options.color : {}; this.connections.filter((ofo) => ofo.participantId == p.participantId).forEach((usr) => { options.name ? usr.user.name = options.name : {}; options._id ? usr.user._id = options._id : {}; From 16b411c64155474b63770ac4d6fa2b69d659efb0 Mon Sep 17 00:00:00 2001 From: Chars chan <28523197+Charsy89@users.noreply.github.com> Date: Thu, 28 May 2020 11:57:54 -0600 Subject: [PATCH 042/135] Ooops... --- src/Room.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Room.js b/src/Room.js index cc0ac12..c437341 100644 --- a/src/Room.js +++ b/src/Room.js @@ -107,7 +107,7 @@ class Room extends EventEmitter { updateParticipant(pid, options) { let p = null; Array.from(this.ppl).map(rpg => { - if(e[1].user._id == pid) p = e[1]; + if(rpg[1].user._id == pid) p = rpg[1]; }); if (p == null) return; options.name ? p.user.name = options.name : {}; From 8b289a4bc3bbd2d308df574ebae9288426f25136 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?charsy=E3=83=81=E3=83=A3=E3=83=BC=E3=82=B7=E3=82=A3?= <28523197+Charsy89@users.noreply.github.com> Date: Mon, 15 Feb 2021 16:52:23 -0700 Subject: [PATCH 043/135] Fix typo, clear interval to be safe --- src/Quota.js | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/Quota.js b/src/Quota.js index da24303..f259672 100644 --- a/src/Quota.js +++ b/src/Quota.js @@ -105,8 +105,9 @@ class Quota { var allowance = params.allowance || this.allowance || Quota.PARAMS_OFFLINE.allowance; var max = params.max || this.max || Quota.PARAMS_OFFLINE.max; var maxHistLen = params.maxHistLen || this.maxHistLen || Quota.PARAMS_OFFLINE.maxHistLen; - let interval = params.interval || 0 - this.inverval = setInterval(() => { + let interval = params.interval || 0; + clearInterval(this.interval); + this.interval = setInterval(() => { this.tick(); }, params.interval) if (allowance !== this.allowance || max !== this.max || maxHistLen !== this.maxHistLen) { @@ -155,4 +156,4 @@ class Quota { }; } -module.exports = Quota \ No newline at end of file +module.exports = Quota From 1c8c328c76ca32e60d7b0f88cc2f7839baeff867 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?charsy=E3=83=81=E3=83=A3=E3=83=BC=E3=82=B7=E3=82=A3?= <28523197+Charsy89@users.noreply.github.com> Date: Tue, 16 Feb 2021 11:48:26 -0700 Subject: [PATCH 044/135] color2 can be anything when creating a new channel --- src/Room.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/Room.js b/src/Room.js index c437341..f319ef8 100644 --- a/src/Room.js +++ b/src/Room.js @@ -421,6 +421,8 @@ class Room extends EventEmitter { if(this.settings){ if(this.settings.color2) msg.set.color2 = this.settings.color2; else delete msg.set.color2; // keep it nice and clean + } else { + delete msg.set.color2; } } }; From 4d99e248c5b6838e278be6481d91a98dc39dd41c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?charsy=E3=83=81=E3=83=A3=E3=83=BC=E3=82=B7=E3=82=A3?= Date: Sun, 28 Feb 2021 21:04:31 -0700 Subject: [PATCH 045/135] thanks kazukazu123123 (#14) --- src/Message.js | 20 +++++++++----------- src/Room.js | 12 ++++++------ 2 files changed, 15 insertions(+), 17 deletions(-) diff --git a/src/Message.js b/src/Message.js index 563dedc..40e72bf 100644 --- a/src/Message.js +++ b/src/Message.js @@ -31,20 +31,16 @@ module.exports = (cl) => { cl.setChannel(msg._id, msg.set); let param; if (cl.channel.isLobby(cl.channel._id)) { - param = Quota.N_PARAMS_LOBBY; - param.m = "nq"; - cl.sendArray([param]) + param = Quota.N_PARAMS_LOBBY; } else { if (!(cl.user._id == cl.channel.crown.userId)) { - param = Quota.N_PARAMS_NORMAL; - param.m = "nq"; - cl.sendArray([param]) + param = Quota.N_PARAMS_NORMAL; } else { - param = Quota.N_PARAMS_RIDICULOUS; - param.m = "nq"; - cl.sendArray([param]) + param = Quota.N_PARAMS_RIDICULOUS; } } + param.m = "nq"; + cl.sendArray([param]) } }) cl.on("m", (msg, admin) => { @@ -141,7 +137,7 @@ module.exports = (cl) => { 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.name.attempt()) return; + if(!cl.quotas.name.attempt()) return; cl.user.name = msg.set.name; let user = new User(cl); user.getUserData().then((usr) => { @@ -159,12 +155,14 @@ module.exports = (cl) => { } }) 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 (msg.hasOwnProperty('_id') && typeof msg._id == "string") { if (!cl.quotas.kickban.attempt() && !admin) return; let _id = msg._id; - let ms = msg.ms || 0; + let ms = msg.ms || 3600000; cl.channel.kickban(_id, ms); } }) diff --git a/src/Room.js b/src/Room.js index f319ef8..15a0a38 100644 --- a/src/Room.js +++ b/src/Room.js @@ -44,8 +44,10 @@ class Room extends EventEmitter { } } this.crowndropped = false; + this.settings = {visible:true,color:this.server.defaultRoomColor,chat:true,crownsolo:false}; } else { //cl.quotas.a.setParams(Quota.PARAMS_A_NORMAL); + this.settings = {visible:true,color:this.server.defaultRoomColor,chat:true,crownsolo:false,lobby:true}; } this.ppl.set(participantId, cl); @@ -63,7 +65,7 @@ class Room extends EventEmitter { m: "c", c: this.chatmsgs.slice(-1 * 32) }]) - this.updateCh(cl); + this.updateCh(cl, this.settings); } else { cl.user.id = otheruser.participantId; cl.participantId = otheruser.participantId; @@ -73,7 +75,7 @@ class Room extends EventEmitter { m: "c", c: this.chatmsgs.slice(-1 * 32) }]) - this.updateCh(cl); + this.updateCh(cl, this.settings); } } @@ -297,13 +299,12 @@ class Room extends EventEmitter { } kickban(_id, ms) { ms = parseInt(ms); - if (ms >= (1000 * 60 * 60 - 500)) return; + if (ms >= (1000 * 60 * 60)) return; if (ms < 0) return; ms = Math.round(ms / 1000) * 1000; let user = this.connections.find((usr) => usr.user._id == _id); if (!user) return; let asd = true; - let tonc = true; let pthatbanned = this.ppl.get(this.crown.participantId); this.connections.filter((usr) => usr.participantId == user.participantId).forEach((u) => { user.bantime = Math.floor(Math.floor(ms / 1000) / 60); @@ -330,7 +331,7 @@ class Room extends EventEmitter { "#room", "short" ) - if (this.crown && (this.crown.userId == _id) && tonc) { + if (this.crown && (this.crown.userId == _id)) { this.Notification("room", "Certificate of Award", `Let it be known that ${user.user.name} kickbanned him/her self.`, @@ -338,7 +339,6 @@ class Room extends EventEmitter { 7000, "#room" ); - tonc = false; } } From 3bb2a49b28f38864c6cf8fa1ebeb324729a58f8f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?charsy=E3=83=81=E3=83=A3=E3=83=BC=E3=82=B7=E3=82=A3?= Date: Sun, 28 Feb 2021 21:06:39 -0700 Subject: [PATCH 046/135] didn't commit these two for some reason --- src/Client.js | 5 ++--- src/Server.js | 1 + 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Client.js b/src/Client.js index df7d72f..c19b37d 100644 --- a/src/Client.js +++ b/src/Client.js @@ -33,14 +33,13 @@ class Client extends EventEmitter { setChannel(_id, settings) { if (this.channel && this.channel._id == _id) return; if (this.server.rooms.get(_id)) { - let room = this.server.rooms.get(_id); + let room = this.server.rooms.get(_id, settings); let userbanned = room.bans.get(this.user._id); if (userbanned && (Date.now() - userbanned.bannedtime >= userbanned.msbanned)) { room.bans.delete(userbanned.user._id); userbanned = undefined; } if (userbanned) { - console.log(Date.now() - userbanned.bannedtime) room.Notification(this.user._id, "Notice", `Currently banned from \"${_id}\" for ${Math.ceil(Math.floor((userbanned.msbanned - (Date.now() - userbanned.bannedtime)) / 1000) / 60)} minutes.`, @@ -49,6 +48,7 @@ class Client extends EventEmitter { "#room", "short" ); + this.setChannel("test/awkward", settings); return; } let channel = this.channel; @@ -100,7 +100,6 @@ class Client extends EventEmitter { this.connectionid; this.server.connections.delete(this.connectionid); this.destroied = true; - console.log(`Removed Connection ${this.connectionid}.`); } bindEventListeners() { this.ws.on("message", (evt, admin) => { diff --git a/src/Server.js b/src/Server.js index afd7ae2..feff000 100644 --- a/src/Server.js +++ b/src/Server.js @@ -1,5 +1,6 @@ const Client = require("./Client.js"); const banned = require('../banned.json'); + class Server extends EventEmitter { constructor(config) { super(); From 629179e18704cb0116c2e33e8cafa83b661cbe58 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?charsy=E3=83=81=E3=83=A3=E3=83=BC=E3=82=B7=E3=82=A3?= Date: Sun, 28 Feb 2021 21:17:50 -0700 Subject: [PATCH 047/135] forgot --- src/Client.js | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Client.js b/src/Client.js index c19b37d..afb3ce9 100644 --- a/src/Client.js +++ b/src/Client.js @@ -100,6 +100,7 @@ class Client extends EventEmitter { this.connectionid; this.server.connections.delete(this.connectionid); this.destroied = true; + console.log(`Removed Connection ${this.connectionid}.`); } bindEventListeners() { this.ws.on("message", (evt, admin) => { From 7051cfd9da4855b12f1bbc6eb05b00181d29ef8d Mon Sep 17 00:00:00 2001 From: Hri7566 Date: Sat, 20 Mar 2021 19:12:38 +0000 Subject: [PATCH 048/135] add dotenv --- .env | 2 + config.js | 4 +- index.js | 3 + node_modules/.package-lock.json | 122 + node_modules/asyncconsole/LICENSE | 661 ++++ node_modules/asyncconsole/README.md | 14 + node_modules/asyncconsole/index.js | 189 ++ node_modules/asyncconsole/package.json | 23 + node_modules/asyncconsole/test.js | 5 + node_modules/bindings/LICENSE.md | 22 + node_modules/bindings/README.md | 98 + node_modules/bindings/bindings.js | 221 ++ node_modules/bindings/package.json | 28 + node_modules/colors/LICENSE | 25 + node_modules/colors/README.md | 221 ++ node_modules/colors/examples/normal-usage.js | 82 + node_modules/colors/examples/safe-string.js | 79 + node_modules/colors/index.d.ts | 136 + node_modules/colors/lib/colors.js | 211 ++ node_modules/colors/lib/custom/trap.js | 46 + node_modules/colors/lib/custom/zalgo.js | 110 + .../colors/lib/extendStringPrototype.js | 110 + node_modules/colors/lib/index.js | 13 + node_modules/colors/lib/maps/america.js | 10 + node_modules/colors/lib/maps/rainbow.js | 12 + node_modules/colors/lib/maps/random.js | 11 + node_modules/colors/lib/maps/zebra.js | 5 + node_modules/colors/lib/styles.js | 95 + node_modules/colors/lib/system/has-flag.js | 35 + .../colors/lib/system/supports-colors.js | 151 + node_modules/colors/package.json | 45 + node_modules/colors/safe.d.ts | 48 + node_modules/colors/safe.js | 10 + node_modules/colors/themes/generic-logging.js | 12 + node_modules/dotenv/CHANGELOG.md | 155 + node_modules/dotenv/LICENSE | 23 + node_modules/dotenv/README.md | 271 ++ node_modules/dotenv/config.js | 11 + node_modules/dotenv/lib/cli-options.js | 13 + node_modules/dotenv/lib/env-options.js | 18 + node_modules/dotenv/lib/main.js | 113 + node_modules/dotenv/package.json | 51 + node_modules/dotenv/types/index.d.ts | 59 + node_modules/dotenv/types/test.ts | 19 + node_modules/dotenv/types/tsconfig.json | 15 + node_modules/dotenv/types/tslint.json | 6 + node_modules/events/.airtap.yml | 15 + node_modules/events/.github/FUNDING.yml | 12 + node_modules/events/.travis.yml | 18 + node_modules/events/History.md | 118 + node_modules/events/LICENSE | 22 + node_modules/events/Readme.md | 50 + node_modules/events/events.js | 497 +++ node_modules/events/package.json | 37 + node_modules/events/security.md | 10 + node_modules/events/tests/add-listeners.js | 111 + .../events/tests/check-listener-leaks.js | 101 + node_modules/events/tests/common.js | 104 + node_modules/events/tests/errors.js | 13 + node_modules/events/tests/events-list.js | 28 + node_modules/events/tests/events-once.js | 234 ++ node_modules/events/tests/index.js | 64 + node_modules/events/tests/legacy-compat.js | 16 + node_modules/events/tests/listener-count.js | 37 + .../events/tests/listeners-side-effects.js | 56 + node_modules/events/tests/listeners.js | 168 + node_modules/events/tests/max-listeners.js | 47 + node_modules/events/tests/method-names.js | 35 + node_modules/events/tests/modify-in-emit.js | 90 + node_modules/events/tests/num-args.js | 60 + node_modules/events/tests/once.js | 83 + node_modules/events/tests/prepend.js | 31 + .../events/tests/remove-all-listeners.js | 133 + node_modules/events/tests/remove-listeners.js | 212 ++ .../tests/set-max-listeners-side-effects.js | 31 + .../events/tests/special-event-names.js | 45 + node_modules/events/tests/subclass.js | 66 + node_modules/events/tests/symbols.js | 25 + node_modules/file-uri-to-path/.npmignore | 1 + node_modules/file-uri-to-path/.travis.yml | 30 + node_modules/file-uri-to-path/History.md | 21 + node_modules/file-uri-to-path/LICENSE | 20 + node_modules/file-uri-to-path/README.md | 74 + node_modules/file-uri-to-path/index.d.ts | 2 + node_modules/file-uri-to-path/index.js | 66 + node_modules/file-uri-to-path/package.json | 32 + node_modules/file-uri-to-path/test/test.js | 24 + node_modules/file-uri-to-path/test/tests.json | 13 + node_modules/inherits/LICENSE | 16 + node_modules/inherits/README.md | 42 + node_modules/inherits/inherits.js | 9 + node_modules/inherits/inherits_browser.js | 27 + node_modules/inherits/package.json | 29 + node_modules/keccak/LICENSE | 21 + node_modules/keccak/README.md | 70 + node_modules/keccak/binding.gyp | 45 + node_modules/keccak/bindings.js | 2 + node_modules/keccak/build/Makefile | 324 ++ .../build/Release/.deps/Release/keccak.node.d | 1 + .../.deps/Release/obj.target/keccak.node.d | 1 + .../Release/obj.target/keccak/src/addon.o.d | 72 + .../src/libkeccak-64/KeccakP-1600-opt64.o.d | 14 + .../libkeccak-64/KeccakSpongeWidth1600.o.d | 16 + node_modules/keccak/build/Release/keccak.node | Bin 0 -> 89848 bytes .../build/Release/obj.target/keccak.node | Bin 0 -> 89848 bytes .../Release/obj.target/keccak/src/addon.o | Bin 0 -> 30216 bytes .../src/libkeccak-64/KeccakP-1600-opt64.o | Bin 0 -> 55416 bytes .../src/libkeccak-64/KeccakSpongeWidth1600.o | Bin 0 -> 7480 bytes node_modules/keccak/build/binding.Makefile | 6 + node_modules/keccak/build/config.gypi | 92 + node_modules/keccak/build/keccak.target.mk | 178 + node_modules/keccak/index.js | 10 + node_modules/keccak/js.js | 2 + node_modules/keccak/lib/api/index.js | 28 + node_modules/keccak/lib/api/keccak.js | 84 + node_modules/keccak/lib/api/shake.js | 75 + .../keccak/lib/keccak-state-reference.js | 144 + .../keccak/lib/keccak-state-unroll.js | 187 ++ node_modules/keccak/lib/keccak.js | 70 + node_modules/keccak/package.json | 60 + node_modules/keccak/src/README.md | 28 + node_modules/keccak/src/addon.cc | 109 + .../src/libkeccak-32/KeccakP-1600-SnP.h | 38 + .../libkeccak-32/KeccakP-1600-inplace32BI.c | 1162 +++++++ .../src/libkeccak-32/KeccakSponge-common.h | 35 + .../keccak/src/libkeccak-32/KeccakSponge.inc | 311 ++ .../src/libkeccak-32/KeccakSpongeWidth1600.c | 54 + .../src/libkeccak-32/KeccakSpongeWidth1600.h | 31 + .../keccak/src/libkeccak-32/SnP-Relaned.h | 140 + node_modules/keccak/src/libkeccak-32/align.h | 32 + .../keccak/src/libkeccak-32/brg_endian.h | 143 + .../src/libkeccak-64/KeccakP-1600-64.macros | 745 +++++ .../src/libkeccak-64/KeccakP-1600-SnP.h | 51 + .../libkeccak-64/KeccakP-1600-opt64-config.h | 6 + .../src/libkeccak-64/KeccakP-1600-opt64.c | 564 ++++ .../KeccakP-1600-unrolling.macros | 302 ++ .../src/libkeccak-64/KeccakSponge-common.h | 35 + .../keccak/src/libkeccak-64/KeccakSponge.inc | 311 ++ .../src/libkeccak-64/KeccakSpongeWidth1600.c | 54 + .../src/libkeccak-64/KeccakSpongeWidth1600.h | 31 + .../keccak/src/libkeccak-64/SnP-Relaned.h | 140 + node_modules/keccak/src/libkeccak-64/align.h | 32 + .../keccak/src/libkeccak-64/brg_endian.h | 143 + node_modules/nan/CHANGELOG.md | 537 +++ node_modules/nan/LICENSE.md | 13 + node_modules/nan/README.md | 455 +++ node_modules/nan/doc/asyncworker.md | 146 + node_modules/nan/doc/buffers.md | 54 + node_modules/nan/doc/callback.md | 76 + node_modules/nan/doc/converters.md | 41 + node_modules/nan/doc/errors.md | 226 ++ node_modules/nan/doc/json.md | 62 + node_modules/nan/doc/maybe_types.md | 583 ++++ node_modules/nan/doc/methods.md | 664 ++++ node_modules/nan/doc/new.md | 147 + node_modules/nan/doc/node_misc.md | 123 + node_modules/nan/doc/object_wrappers.md | 263 ++ node_modules/nan/doc/persistent.md | 296 ++ node_modules/nan/doc/scopes.md | 73 + node_modules/nan/doc/script.md | 38 + node_modules/nan/doc/string_bytes.md | 62 + node_modules/nan/doc/v8_internals.md | 199 ++ node_modules/nan/doc/v8_misc.md | 85 + node_modules/nan/include_dirs.js | 1 + node_modules/nan/nan.h | 2898 +++++++++++++++++ node_modules/nan/nan_callbacks.h | 88 + node_modules/nan/nan_callbacks_12_inl.h | 514 +++ node_modules/nan/nan_callbacks_pre_12_inl.h | 520 +++ node_modules/nan/nan_converters.h | 72 + node_modules/nan/nan_converters_43_inl.h | 68 + node_modules/nan/nan_converters_pre_43_inl.h | 42 + .../nan/nan_define_own_property_helper.h | 29 + node_modules/nan/nan_implementation_12_inl.h | 430 +++ .../nan/nan_implementation_pre_12_inl.h | 263 ++ node_modules/nan/nan_json.h | 166 + node_modules/nan/nan_maybe_43_inl.h | 356 ++ node_modules/nan/nan_maybe_pre_43_inl.h | 268 ++ node_modules/nan/nan_new.h | 340 ++ node_modules/nan/nan_object_wrap.h | 156 + node_modules/nan/nan_persistent_12_inl.h | 132 + node_modules/nan/nan_persistent_pre_12_inl.h | 242 ++ node_modules/nan/nan_private.h | 73 + node_modules/nan/nan_string_bytes.h | 305 ++ node_modules/nan/nan_typedarray_contents.h | 96 + node_modules/nan/nan_weak.h | 437 +++ node_modules/nan/package.json | 37 + node_modules/nan/tools/1to2.js | 412 +++ node_modules/nan/tools/README.md | 14 + node_modules/nan/tools/package.json | 19 + .../node-json-color-stringify/.npmignore | 21 + .../node-json-color-stringify/LICENSE.md | 21 + .../node-json-color-stringify/README.MD | 59 + .../examples/example.js | 21 + .../node-json-color-stringify/img/mac.png | Bin 0 -> 73722 bytes .../node-json-color-stringify/index.js | 67 + .../node-json-color-stringify/package.json | 22 + node_modules/safe-buffer/LICENSE | 21 + node_modules/safe-buffer/README.md | 584 ++++ node_modules/safe-buffer/index.d.ts | 187 ++ node_modules/safe-buffer/index.js | 65 + node_modules/safe-buffer/package.json | 51 + node_modules/ws/LICENSE | 21 + node_modules/ws/README.md | 496 +++ node_modules/ws/browser.js | 8 + node_modules/ws/index.js | 10 + node_modules/ws/lib/buffer-util.js | 129 + node_modules/ws/lib/constants.js | 10 + node_modules/ws/lib/event-target.js | 184 ++ node_modules/ws/lib/extension.js | 223 ++ node_modules/ws/lib/limiter.js | 55 + node_modules/ws/lib/permessage-deflate.js | 517 +++ node_modules/ws/lib/receiver.js | 507 +++ node_modules/ws/lib/sender.js | 405 +++ node_modules/ws/lib/stream.js | 165 + node_modules/ws/lib/validation.js | 30 + node_modules/ws/lib/websocket-server.js | 406 +++ node_modules/ws/lib/websocket.js | 933 ++++++ node_modules/ws/package.json | 56 + package-lock.json | 210 ++ package.json | 4 +- src/TODO.txt | 2 - 221 files changed, 30192 insertions(+), 6 deletions(-) create mode 100644 .env create mode 100644 node_modules/.package-lock.json create mode 100644 node_modules/asyncconsole/LICENSE create mode 100644 node_modules/asyncconsole/README.md create mode 100644 node_modules/asyncconsole/index.js create mode 100644 node_modules/asyncconsole/package.json create mode 100644 node_modules/asyncconsole/test.js create mode 100644 node_modules/bindings/LICENSE.md create mode 100644 node_modules/bindings/README.md create mode 100644 node_modules/bindings/bindings.js create mode 100644 node_modules/bindings/package.json create mode 100644 node_modules/colors/LICENSE create mode 100644 node_modules/colors/README.md create mode 100644 node_modules/colors/examples/normal-usage.js create mode 100644 node_modules/colors/examples/safe-string.js create mode 100644 node_modules/colors/index.d.ts create mode 100644 node_modules/colors/lib/colors.js create mode 100644 node_modules/colors/lib/custom/trap.js create mode 100644 node_modules/colors/lib/custom/zalgo.js create mode 100644 node_modules/colors/lib/extendStringPrototype.js create mode 100644 node_modules/colors/lib/index.js create mode 100644 node_modules/colors/lib/maps/america.js create mode 100644 node_modules/colors/lib/maps/rainbow.js create mode 100644 node_modules/colors/lib/maps/random.js create mode 100644 node_modules/colors/lib/maps/zebra.js create mode 100644 node_modules/colors/lib/styles.js create mode 100644 node_modules/colors/lib/system/has-flag.js create mode 100644 node_modules/colors/lib/system/supports-colors.js create mode 100644 node_modules/colors/package.json create mode 100644 node_modules/colors/safe.d.ts create mode 100644 node_modules/colors/safe.js create mode 100644 node_modules/colors/themes/generic-logging.js create mode 100644 node_modules/dotenv/CHANGELOG.md create mode 100644 node_modules/dotenv/LICENSE create mode 100644 node_modules/dotenv/README.md create mode 100644 node_modules/dotenv/config.js create mode 100644 node_modules/dotenv/lib/cli-options.js create mode 100644 node_modules/dotenv/lib/env-options.js create mode 100644 node_modules/dotenv/lib/main.js create mode 100644 node_modules/dotenv/package.json create mode 100644 node_modules/dotenv/types/index.d.ts create mode 100644 node_modules/dotenv/types/test.ts create mode 100644 node_modules/dotenv/types/tsconfig.json create mode 100644 node_modules/dotenv/types/tslint.json create mode 100644 node_modules/events/.airtap.yml create mode 100644 node_modules/events/.github/FUNDING.yml create mode 100644 node_modules/events/.travis.yml create mode 100644 node_modules/events/History.md create mode 100644 node_modules/events/LICENSE create mode 100644 node_modules/events/Readme.md create mode 100644 node_modules/events/events.js create mode 100644 node_modules/events/package.json create mode 100644 node_modules/events/security.md create mode 100644 node_modules/events/tests/add-listeners.js create mode 100644 node_modules/events/tests/check-listener-leaks.js create mode 100644 node_modules/events/tests/common.js create mode 100644 node_modules/events/tests/errors.js create mode 100644 node_modules/events/tests/events-list.js create mode 100644 node_modules/events/tests/events-once.js create mode 100644 node_modules/events/tests/index.js create mode 100644 node_modules/events/tests/legacy-compat.js create mode 100644 node_modules/events/tests/listener-count.js create mode 100644 node_modules/events/tests/listeners-side-effects.js create mode 100644 node_modules/events/tests/listeners.js create mode 100644 node_modules/events/tests/max-listeners.js create mode 100644 node_modules/events/tests/method-names.js create mode 100644 node_modules/events/tests/modify-in-emit.js create mode 100644 node_modules/events/tests/num-args.js create mode 100644 node_modules/events/tests/once.js create mode 100644 node_modules/events/tests/prepend.js create mode 100644 node_modules/events/tests/remove-all-listeners.js create mode 100644 node_modules/events/tests/remove-listeners.js create mode 100644 node_modules/events/tests/set-max-listeners-side-effects.js create mode 100644 node_modules/events/tests/special-event-names.js create mode 100644 node_modules/events/tests/subclass.js create mode 100644 node_modules/events/tests/symbols.js create mode 100644 node_modules/file-uri-to-path/.npmignore create mode 100644 node_modules/file-uri-to-path/.travis.yml create mode 100644 node_modules/file-uri-to-path/History.md create mode 100644 node_modules/file-uri-to-path/LICENSE create mode 100644 node_modules/file-uri-to-path/README.md create mode 100644 node_modules/file-uri-to-path/index.d.ts create mode 100644 node_modules/file-uri-to-path/index.js create mode 100644 node_modules/file-uri-to-path/package.json create mode 100644 node_modules/file-uri-to-path/test/test.js create mode 100644 node_modules/file-uri-to-path/test/tests.json create mode 100644 node_modules/inherits/LICENSE create mode 100644 node_modules/inherits/README.md create mode 100644 node_modules/inherits/inherits.js create mode 100644 node_modules/inherits/inherits_browser.js create mode 100644 node_modules/inherits/package.json create mode 100644 node_modules/keccak/LICENSE create mode 100644 node_modules/keccak/README.md create mode 100644 node_modules/keccak/binding.gyp create mode 100644 node_modules/keccak/bindings.js create mode 100644 node_modules/keccak/build/Makefile create mode 100644 node_modules/keccak/build/Release/.deps/Release/keccak.node.d create mode 100644 node_modules/keccak/build/Release/.deps/Release/obj.target/keccak.node.d create mode 100644 node_modules/keccak/build/Release/.deps/Release/obj.target/keccak/src/addon.o.d create mode 100644 node_modules/keccak/build/Release/.deps/Release/obj.target/keccak/src/libkeccak-64/KeccakP-1600-opt64.o.d create mode 100644 node_modules/keccak/build/Release/.deps/Release/obj.target/keccak/src/libkeccak-64/KeccakSpongeWidth1600.o.d create mode 100755 node_modules/keccak/build/Release/keccak.node create mode 100755 node_modules/keccak/build/Release/obj.target/keccak.node create mode 100644 node_modules/keccak/build/Release/obj.target/keccak/src/addon.o create mode 100644 node_modules/keccak/build/Release/obj.target/keccak/src/libkeccak-64/KeccakP-1600-opt64.o create mode 100644 node_modules/keccak/build/Release/obj.target/keccak/src/libkeccak-64/KeccakSpongeWidth1600.o create mode 100644 node_modules/keccak/build/binding.Makefile create mode 100644 node_modules/keccak/build/config.gypi create mode 100644 node_modules/keccak/build/keccak.target.mk create mode 100644 node_modules/keccak/index.js create mode 100644 node_modules/keccak/js.js create mode 100644 node_modules/keccak/lib/api/index.js create mode 100644 node_modules/keccak/lib/api/keccak.js create mode 100644 node_modules/keccak/lib/api/shake.js create mode 100644 node_modules/keccak/lib/keccak-state-reference.js create mode 100644 node_modules/keccak/lib/keccak-state-unroll.js create mode 100644 node_modules/keccak/lib/keccak.js create mode 100644 node_modules/keccak/package.json create mode 100644 node_modules/keccak/src/README.md create mode 100644 node_modules/keccak/src/addon.cc create mode 100644 node_modules/keccak/src/libkeccak-32/KeccakP-1600-SnP.h create mode 100644 node_modules/keccak/src/libkeccak-32/KeccakP-1600-inplace32BI.c create mode 100644 node_modules/keccak/src/libkeccak-32/KeccakSponge-common.h create mode 100644 node_modules/keccak/src/libkeccak-32/KeccakSponge.inc create mode 100644 node_modules/keccak/src/libkeccak-32/KeccakSpongeWidth1600.c create mode 100644 node_modules/keccak/src/libkeccak-32/KeccakSpongeWidth1600.h create mode 100644 node_modules/keccak/src/libkeccak-32/SnP-Relaned.h create mode 100644 node_modules/keccak/src/libkeccak-32/align.h create mode 100644 node_modules/keccak/src/libkeccak-32/brg_endian.h create mode 100644 node_modules/keccak/src/libkeccak-64/KeccakP-1600-64.macros create mode 100644 node_modules/keccak/src/libkeccak-64/KeccakP-1600-SnP.h create mode 100644 node_modules/keccak/src/libkeccak-64/KeccakP-1600-opt64-config.h create mode 100644 node_modules/keccak/src/libkeccak-64/KeccakP-1600-opt64.c create mode 100644 node_modules/keccak/src/libkeccak-64/KeccakP-1600-unrolling.macros create mode 100644 node_modules/keccak/src/libkeccak-64/KeccakSponge-common.h create mode 100644 node_modules/keccak/src/libkeccak-64/KeccakSponge.inc create mode 100644 node_modules/keccak/src/libkeccak-64/KeccakSpongeWidth1600.c create mode 100644 node_modules/keccak/src/libkeccak-64/KeccakSpongeWidth1600.h create mode 100644 node_modules/keccak/src/libkeccak-64/SnP-Relaned.h create mode 100644 node_modules/keccak/src/libkeccak-64/align.h create mode 100644 node_modules/keccak/src/libkeccak-64/brg_endian.h create mode 100644 node_modules/nan/CHANGELOG.md create mode 100644 node_modules/nan/LICENSE.md create mode 100644 node_modules/nan/README.md create mode 100644 node_modules/nan/doc/asyncworker.md create mode 100644 node_modules/nan/doc/buffers.md create mode 100644 node_modules/nan/doc/callback.md create mode 100644 node_modules/nan/doc/converters.md create mode 100644 node_modules/nan/doc/errors.md create mode 100644 node_modules/nan/doc/json.md create mode 100644 node_modules/nan/doc/maybe_types.md create mode 100644 node_modules/nan/doc/methods.md create mode 100644 node_modules/nan/doc/new.md create mode 100644 node_modules/nan/doc/node_misc.md create mode 100644 node_modules/nan/doc/object_wrappers.md create mode 100644 node_modules/nan/doc/persistent.md create mode 100644 node_modules/nan/doc/scopes.md create mode 100644 node_modules/nan/doc/script.md create mode 100644 node_modules/nan/doc/string_bytes.md create mode 100644 node_modules/nan/doc/v8_internals.md create mode 100644 node_modules/nan/doc/v8_misc.md create mode 100644 node_modules/nan/include_dirs.js create mode 100644 node_modules/nan/nan.h create mode 100644 node_modules/nan/nan_callbacks.h create mode 100644 node_modules/nan/nan_callbacks_12_inl.h create mode 100644 node_modules/nan/nan_callbacks_pre_12_inl.h create mode 100644 node_modules/nan/nan_converters.h create mode 100644 node_modules/nan/nan_converters_43_inl.h create mode 100644 node_modules/nan/nan_converters_pre_43_inl.h create mode 100644 node_modules/nan/nan_define_own_property_helper.h create mode 100644 node_modules/nan/nan_implementation_12_inl.h create mode 100644 node_modules/nan/nan_implementation_pre_12_inl.h create mode 100644 node_modules/nan/nan_json.h create mode 100644 node_modules/nan/nan_maybe_43_inl.h create mode 100644 node_modules/nan/nan_maybe_pre_43_inl.h create mode 100644 node_modules/nan/nan_new.h create mode 100644 node_modules/nan/nan_object_wrap.h create mode 100644 node_modules/nan/nan_persistent_12_inl.h create mode 100644 node_modules/nan/nan_persistent_pre_12_inl.h create mode 100644 node_modules/nan/nan_private.h create mode 100644 node_modules/nan/nan_string_bytes.h create mode 100644 node_modules/nan/nan_typedarray_contents.h create mode 100644 node_modules/nan/nan_weak.h create mode 100644 node_modules/nan/package.json create mode 100755 node_modules/nan/tools/1to2.js create mode 100644 node_modules/nan/tools/README.md create mode 100644 node_modules/nan/tools/package.json create mode 100644 node_modules/node-json-color-stringify/.npmignore create mode 100644 node_modules/node-json-color-stringify/LICENSE.md create mode 100644 node_modules/node-json-color-stringify/README.MD create mode 100644 node_modules/node-json-color-stringify/examples/example.js create mode 100644 node_modules/node-json-color-stringify/img/mac.png create mode 100644 node_modules/node-json-color-stringify/index.js create mode 100644 node_modules/node-json-color-stringify/package.json create mode 100644 node_modules/safe-buffer/LICENSE create mode 100644 node_modules/safe-buffer/README.md create mode 100644 node_modules/safe-buffer/index.d.ts create mode 100644 node_modules/safe-buffer/index.js create mode 100644 node_modules/safe-buffer/package.json create mode 100644 node_modules/ws/LICENSE create mode 100644 node_modules/ws/README.md create mode 100644 node_modules/ws/browser.js create mode 100644 node_modules/ws/index.js create mode 100644 node_modules/ws/lib/buffer-util.js create mode 100644 node_modules/ws/lib/constants.js create mode 100644 node_modules/ws/lib/event-target.js create mode 100644 node_modules/ws/lib/extension.js create mode 100644 node_modules/ws/lib/limiter.js create mode 100644 node_modules/ws/lib/permessage-deflate.js create mode 100644 node_modules/ws/lib/receiver.js create mode 100644 node_modules/ws/lib/sender.js create mode 100644 node_modules/ws/lib/stream.js create mode 100644 node_modules/ws/lib/validation.js create mode 100644 node_modules/ws/lib/websocket-server.js create mode 100644 node_modules/ws/lib/websocket.js create mode 100644 node_modules/ws/package.json create mode 100644 package-lock.json delete mode 100644 src/TODO.txt diff --git a/.env b/.env new file mode 100644 index 0000000..b553ebc --- /dev/null +++ b/.env @@ -0,0 +1,2 @@ +ADMINPASS=put_password_here +SALT=seed_here diff --git a/config.js b/config.js index 0497b8a..c9ab3fc 100644 --- a/config.js +++ b/config.js @@ -1,10 +1,10 @@ module.exports = Object.seal({ port: "8080", motd: "You agree to read this message.", - _id_PrivateKey: "boppity", + _id_PrivateKey: process.env.SALT, defaultUsername: "Anonymous", defaultRoomColor: "#3b5054", defaultLobbyColor: "#19b4b9", defaultLobbyColor2: "#801014", - adminpass: "adminpass" + adminpass: process.env.ADMINPASS }) diff --git a/index.js b/index.js index 3f047d8..2363750 100644 --- a/index.js +++ b/index.js @@ -1,3 +1,6 @@ +// dotenv to keep secret variables in (they won't show on github) +require('dotenv').config(); + //call new Server global.WebSocket = require('ws'); global.EventEmitter = require('events').EventEmitter; diff --git a/node_modules/.package-lock.json b/node_modules/.package-lock.json new file mode 100644 index 0000000..b1fbe29 --- /dev/null +++ b/node_modules/.package-lock.json @@ -0,0 +1,122 @@ +{ + "name": "mpp-server-master", + "version": "1.0.0", + "lockfileVersion": 2, + "requires": true, + "packages": { + "node_modules/asyncconsole": { + "version": "1.3.9", + "resolved": "https://registry.npmjs.org/asyncconsole/-/asyncconsole-1.3.9.tgz", + "integrity": "sha1-+YpGz4b1ix0I43grYMaLhCLLtgY=" + }, + "node_modules/bindings": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/bindings/-/bindings-1.5.0.tgz", + "integrity": "sha512-p2q/t/mhvuOj/UeLlV6566GD/guowlr0hHxClI0W9m7MWYkL1F0hLo+0Aexs9HSPCtR1SXQ0TD3MMKrXZajbiQ==", + "dependencies": { + "file-uri-to-path": "1.0.0" + } + }, + "node_modules/colors": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/colors/-/colors-1.4.0.tgz", + "integrity": "sha512-a+UqTh4kgZg/SlGvfbzDHpgRu7AAQOmmqRHJnxhRZICKFUT91brVhNNt58CMWU9PsBbv3PDCZUHbVxuDiH2mtA==", + "engines": { + "node": ">=0.1.90" + } + }, + "node_modules/dotenv": { + "version": "8.2.0", + "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-8.2.0.tgz", + "integrity": "sha512-8sJ78ElpbDJBHNeBzUbUVLsqKdccaa/BXF1uPTw3GrvQTBgrQrtObr2mUrE38vzYd8cEv+m/JBfDLioYcfXoaw==", + "engines": { + "node": ">=8" + } + }, + "node_modules/events": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/events/-/events-3.3.0.tgz", + "integrity": "sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==", + "engines": { + "node": ">=0.8.x" + } + }, + "node_modules/file-uri-to-path": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/file-uri-to-path/-/file-uri-to-path-1.0.0.tgz", + "integrity": "sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw==" + }, + "node_modules/inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" + }, + "node_modules/keccak": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/keccak/-/keccak-2.1.0.tgz", + "integrity": "sha512-m1wbJRTo+gWbctZWay9i26v5fFnYkOn7D5PCxJ3fZUGUEb49dE1Pm4BREUYCt/aoO6di7jeoGmhvqN9Nzylm3Q==", + "hasInstallScript": true, + "dependencies": { + "bindings": "^1.5.0", + "inherits": "^2.0.4", + "nan": "^2.14.0", + "safe-buffer": "^5.2.0" + }, + "engines": { + "node": ">=5.12.0" + } + }, + "node_modules/nan": { + "version": "2.14.2", + "resolved": "https://registry.npmjs.org/nan/-/nan-2.14.2.tgz", + "integrity": "sha512-M2ufzIiINKCuDfBSAUr1vWQ+vuVcA9kqx8JJUsbQi6yf1uGRyb7HfpdfUr5qLXf3B/t8dPvcjhKMmlfnP47EzQ==" + }, + "node_modules/node-json-color-stringify": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/node-json-color-stringify/-/node-json-color-stringify-1.1.0.tgz", + "integrity": "sha1-i7Ek+ROFlZEFgCZRMSHWYJ1u9bc=", + "dependencies": { + "colors": "^1.1.2" + } + }, + "node_modules/safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/ws": { + "version": "7.4.4", + "resolved": "https://registry.npmjs.org/ws/-/ws-7.4.4.tgz", + "integrity": "sha512-Qm8k8ojNQIMx7S+Zp8u/uHOx7Qazv3Yv4q68MiWWWOJhiwG5W3x7iqmRtJo8xxrciZUY4vRxUTJCKuRnF28ZZw==", + "engines": { + "node": ">=8.3.0" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": "^5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } + } + } + } +} diff --git a/node_modules/asyncconsole/LICENSE b/node_modules/asyncconsole/LICENSE new file mode 100644 index 0000000..dbbe355 --- /dev/null +++ b/node_modules/asyncconsole/LICENSE @@ -0,0 +1,661 @@ + GNU AFFERO GENERAL PUBLIC LICENSE + Version 3, 19 November 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The GNU Affero General Public License is a free, copyleft license for +software and other kinds of works, specifically designed to ensure +cooperation with the community in the case of network server software. + + The licenses for most software and other practical works are designed +to take away your freedom to share and change the works. By contrast, +our General Public Licenses are intended to guarantee your freedom to +share and change all versions of a program--to make sure it remains free +software for all its users. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +them if you wish), that you receive source code or can get it if you +want it, that you can change the software or use pieces of it in new +free programs, and that you know you can do these things. + + Developers that use our General Public Licenses protect your rights +with two steps: (1) assert copyright on the software, and (2) offer +you this License which gives you legal permission to copy, distribute +and/or modify the software. + + A secondary benefit of defending all users' freedom is that +improvements made in alternate versions of the program, if they +receive widespread use, become available for other developers to +incorporate. Many developers of free software are heartened and +encouraged by the resulting cooperation. However, in the case of +software used on network servers, this result may fail to come about. +The GNU General Public License permits making a modified version and +letting the public access it on a server without ever releasing its +source code to the public. + + The GNU Affero General Public License is designed specifically to +ensure that, in such cases, the modified source code becomes available +to the community. It requires the operator of a network server to +provide the source code of the modified version running there to the +users of that server. Therefore, public use of a modified version, on +a publicly accessible server, gives the public access to the source +code of the modified version. + + An older license, called the Affero General Public License and +published by Affero, was designed to accomplish similar goals. This is +a different license, not a version of the Affero GPL, but Affero has +released a new version of the Affero GPL which permits relicensing under +this license. + + The precise terms and conditions for copying, distribution and +modification follow. + + TERMS AND CONDITIONS + + 0. Definitions. + + "This License" refers to version 3 of the GNU Affero General Public License. + + "Copyright" also means copyright-like laws that apply to other kinds of +works, such as semiconductor masks. + + "The Program" refers to any copyrightable work licensed under this +License. Each licensee is addressed as "you". "Licensees" and +"recipients" may be individuals or organizations. + + To "modify" a work means to copy from or adapt all or part of the work +in a fashion requiring copyright permission, other than the making of an +exact copy. The resulting work is called a "modified version" of the +earlier work or a work "based on" the earlier work. + + A "covered work" means either the unmodified Program or a work based +on the Program. + + To "propagate" a work means to do anything with it that, without +permission, would make you directly or secondarily liable for +infringement under applicable copyright law, except executing it on a +computer or modifying a private copy. Propagation includes copying, +distribution (with or without modification), making available to the +public, and in some countries other activities as well. + + To "convey" a work means any kind of propagation that enables other +parties to make or receive copies. Mere interaction with a user through +a computer network, with no transfer of a copy, is not conveying. + + An interactive user interface displays "Appropriate Legal Notices" +to the extent that it includes a convenient and prominently visible +feature that (1) displays an appropriate copyright notice, and (2) +tells the user that there is no warranty for the work (except to the +extent that warranties are provided), that licensees may convey the +work under this License, and how to view a copy of this License. If +the interface presents a list of user commands or options, such as a +menu, a prominent item in the list meets this criterion. + + 1. Source Code. + + The "source code" for a work means the preferred form of the work +for making modifications to it. "Object code" means any non-source +form of a work. + + A "Standard Interface" means an interface that either is an official +standard defined by a recognized standards body, or, in the case of +interfaces specified for a particular programming language, one that +is widely used among developers working in that language. + + The "System Libraries" of an executable work include anything, other +than the work as a whole, that (a) is included in the normal form of +packaging a Major Component, but which is not part of that Major +Component, and (b) serves only to enable use of the work with that +Major Component, or to implement a Standard Interface for which an +implementation is available to the public in source code form. A +"Major Component", in this context, means a major essential component +(kernel, window system, and so on) of the specific operating system +(if any) on which the executable work runs, or a compiler used to +produce the work, or an object code interpreter used to run it. + + The "Corresponding Source" for a work in object code form means all +the source code needed to generate, install, and (for an executable +work) run the object code and to modify the work, including scripts to +control those activities. However, it does not include the work's +System Libraries, or general-purpose tools or generally available free +programs which are used unmodified in performing those activities but +which are not part of the work. For example, Corresponding Source +includes interface definition files associated with source files for +the work, and the source code for shared libraries and dynamically +linked subprograms that the work is specifically designed to require, +such as by intimate data communication or control flow between those +subprograms and other parts of the work. + + The Corresponding Source need not include anything that users +can regenerate automatically from other parts of the Corresponding +Source. + + The Corresponding Source for a work in source code form is that +same work. + + 2. Basic Permissions. + + All rights granted under this License are granted for the term of +copyright on the Program, and are irrevocable provided the stated +conditions are met. This License explicitly affirms your unlimited +permission to run the unmodified Program. The output from running a +covered work is covered by this License only if the output, given its +content, constitutes a covered work. This License acknowledges your +rights of fair use or other equivalent, as provided by copyright law. + + You may make, run and propagate covered works that you do not +convey, without conditions so long as your license otherwise remains +in force. You may convey covered works to others for the sole purpose +of having them make modifications exclusively for you, or provide you +with facilities for running those works, provided that you comply with +the terms of this License in conveying all material for which you do +not control copyright. Those thus making or running the covered works +for you must do so exclusively on your behalf, under your direction +and control, on terms that prohibit them from making any copies of +your copyrighted material outside their relationship with you. + + Conveying under any other circumstances is permitted solely under +the conditions stated below. Sublicensing is not allowed; section 10 +makes it unnecessary. + + 3. Protecting Users' Legal Rights From Anti-Circumvention Law. + + No covered work shall be deemed part of an effective technological +measure under any applicable law fulfilling obligations under article +11 of the WIPO copyright treaty adopted on 20 December 1996, or +similar laws prohibiting or restricting circumvention of such +measures. + + When you convey a covered work, you waive any legal power to forbid +circumvention of technological measures to the extent such circumvention +is effected by exercising rights under this License with respect to +the covered work, and you disclaim any intention to limit operation or +modification of the work as a means of enforcing, against the work's +users, your or third parties' legal rights to forbid circumvention of +technological measures. + + 4. Conveying Verbatim Copies. + + You may convey verbatim copies of the Program's source code as you +receive it, in any medium, provided that you conspicuously and +appropriately publish on each copy an appropriate copyright notice; +keep intact all notices stating that this License and any +non-permissive terms added in accord with section 7 apply to the code; +keep intact all notices of the absence of any warranty; and give all +recipients a copy of this License along with the Program. + + You may charge any price or no price for each copy that you convey, +and you may offer support or warranty protection for a fee. + + 5. Conveying Modified Source Versions. + + You may convey a work based on the Program, or the modifications to +produce it from the Program, in the form of source code under the +terms of section 4, provided that you also meet all of these conditions: + + a) The work must carry prominent notices stating that you modified + it, and giving a relevant date. + + b) The work must carry prominent notices stating that it is + released under this License and any conditions added under section + 7. This requirement modifies the requirement in section 4 to + "keep intact all notices". + + c) You must license the entire work, as a whole, under this + License to anyone who comes into possession of a copy. This + License will therefore apply, along with any applicable section 7 + additional terms, to the whole of the work, and all its parts, + regardless of how they are packaged. This License gives no + permission to license the work in any other way, but it does not + invalidate such permission if you have separately received it. + + d) If the work has interactive user interfaces, each must display + Appropriate Legal Notices; however, if the Program has interactive + interfaces that do not display Appropriate Legal Notices, your + work need not make them do so. + + A compilation of a covered work with other separate and independent +works, which are not by their nature extensions of the covered work, +and which are not combined with it such as to form a larger program, +in or on a volume of a storage or distribution medium, is called an +"aggregate" if the compilation and its resulting copyright are not +used to limit the access or legal rights of the compilation's users +beyond what the individual works permit. Inclusion of a covered work +in an aggregate does not cause this License to apply to the other +parts of the aggregate. + + 6. Conveying Non-Source Forms. + + You may convey a covered work in object code form under the terms +of sections 4 and 5, provided that you also convey the +machine-readable Corresponding Source under the terms of this License, +in one of these ways: + + a) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by the + Corresponding Source fixed on a durable physical medium + customarily used for software interchange. + + b) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by a + written offer, valid for at least three years and valid for as + long as you offer spare parts or customer support for that product + model, to give anyone who possesses the object code either (1) a + copy of the Corresponding Source for all the software in the + product that is covered by this License, on a durable physical + medium customarily used for software interchange, for a price no + more than your reasonable cost of physically performing this + conveying of source, or (2) access to copy the + Corresponding Source from a network server at no charge. + + c) Convey individual copies of the object code with a copy of the + written offer to provide the Corresponding Source. This + alternative is allowed only occasionally and noncommercially, and + only if you received the object code with such an offer, in accord + with subsection 6b. + + d) Convey the object code by offering access from a designated + place (gratis or for a charge), and offer equivalent access to the + Corresponding Source in the same way through the same place at no + further charge. You need not require recipients to copy the + Corresponding Source along with the object code. If the place to + copy the object code is a network server, the Corresponding Source + may be on a different server (operated by you or a third party) + that supports equivalent copying facilities, provided you maintain + clear directions next to the object code saying where to find the + Corresponding Source. Regardless of what server hosts the + Corresponding Source, you remain obligated to ensure that it is + available for as long as needed to satisfy these requirements. + + e) Convey the object code using peer-to-peer transmission, provided + you inform other peers where the object code and Corresponding + Source of the work are being offered to the general public at no + charge under subsection 6d. + + A separable portion of the object code, whose source code is excluded +from the Corresponding Source as a System Library, need not be +included in conveying the object code work. + + A "User Product" is either (1) a "consumer product", which means any +tangible personal property which is normally used for personal, family, +or household purposes, or (2) anything designed or sold for incorporation +into a dwelling. In determining whether a product is a consumer product, +doubtful cases shall be resolved in favor of coverage. For a particular +product received by a particular user, "normally used" refers to a +typical or common use of that class of product, regardless of the status +of the particular user or of the way in which the particular user +actually uses, or expects or is expected to use, the product. A product +is a consumer product regardless of whether the product has substantial +commercial, industrial or non-consumer uses, unless such uses represent +the only significant mode of use of the product. + + "Installation Information" for a User Product means any methods, +procedures, authorization keys, or other information required to install +and execute modified versions of a covered work in that User Product from +a modified version of its Corresponding Source. The information must +suffice to ensure that the continued functioning of the modified object +code is in no case prevented or interfered with solely because +modification has been made. + + If you convey an object code work under this section in, or with, or +specifically for use in, a User Product, and the conveying occurs as +part of a transaction in which the right of possession and use of the +User Product is transferred to the recipient in perpetuity or for a +fixed term (regardless of how the transaction is characterized), the +Corresponding Source conveyed under this section must be accompanied +by the Installation Information. But this requirement does not apply +if neither you nor any third party retains the ability to install +modified object code on the User Product (for example, the work has +been installed in ROM). + + The requirement to provide Installation Information does not include a +requirement to continue to provide support service, warranty, or updates +for a work that has been modified or installed by the recipient, or for +the User Product in which it has been modified or installed. Access to a +network may be denied when the modification itself materially and +adversely affects the operation of the network or violates the rules and +protocols for communication across the network. + + Corresponding Source conveyed, and Installation Information provided, +in accord with this section must be in a format that is publicly +documented (and with an implementation available to the public in +source code form), and must require no special password or key for +unpacking, reading or copying. + + 7. Additional Terms. + + "Additional permissions" are terms that supplement the terms of this +License by making exceptions from one or more of its conditions. +Additional permissions that are applicable to the entire Program shall +be treated as though they were included in this License, to the extent +that they are valid under applicable law. If additional permissions +apply only to part of the Program, that part may be used separately +under those permissions, but the entire Program remains governed by +this License without regard to the additional permissions. + + When you convey a copy of a covered work, you may at your option +remove any additional permissions from that copy, or from any part of +it. (Additional permissions may be written to require their own +removal in certain cases when you modify the work.) You may place +additional permissions on material, added by you to a covered work, +for which you have or can give appropriate copyright permission. + + Notwithstanding any other provision of this License, for material you +add to a covered work, you may (if authorized by the copyright holders of +that material) supplement the terms of this License with terms: + + a) Disclaiming warranty or limiting liability differently from the + terms of sections 15 and 16 of this License; or + + b) Requiring preservation of specified reasonable legal notices or + author attributions in that material or in the Appropriate Legal + Notices displayed by works containing it; or + + c) Prohibiting misrepresentation of the origin of that material, or + requiring that modified versions of such material be marked in + reasonable ways as different from the original version; or + + d) Limiting the use for publicity purposes of names of licensors or + authors of the material; or + + e) Declining to grant rights under trademark law for use of some + trade names, trademarks, or service marks; or + + f) Requiring indemnification of licensors and authors of that + material by anyone who conveys the material (or modified versions of + it) with contractual assumptions of liability to the recipient, for + any liability that these contractual assumptions directly impose on + those licensors and authors. + + All other non-permissive additional terms are considered "further +restrictions" within the meaning of section 10. If the Program as you +received it, or any part of it, contains a notice stating that it is +governed by this License along with a term that is a further +restriction, you may remove that term. If a license document contains +a further restriction but permits relicensing or conveying under this +License, you may add to a covered work material governed by the terms +of that license document, provided that the further restriction does +not survive such relicensing or conveying. + + If you add terms to a covered work in accord with this section, you +must place, in the relevant source files, a statement of the +additional terms that apply to those files, or a notice indicating +where to find the applicable terms. + + Additional terms, permissive or non-permissive, may be stated in the +form of a separately written license, or stated as exceptions; +the above requirements apply either way. + + 8. Termination. + + You may not propagate or modify a covered work except as expressly +provided under this License. Any attempt otherwise to propagate or +modify it is void, and will automatically terminate your rights under +this License (including any patent licenses granted under the third +paragraph of section 11). + + However, if you cease all violation of this License, then your +license from a particular copyright holder is reinstated (a) +provisionally, unless and until the copyright holder explicitly and +finally terminates your license, and (b) permanently, if the copyright +holder fails to notify you of the violation by some reasonable means +prior to 60 days after the cessation. + + Moreover, your license from a particular copyright holder is +reinstated permanently if the copyright holder notifies you of the +violation by some reasonable means, this is the first time you have +received notice of violation of this License (for any work) from that +copyright holder, and you cure the violation prior to 30 days after +your receipt of the notice. + + Termination of your rights under this section does not terminate the +licenses of parties who have received copies or rights from you under +this License. If your rights have been terminated and not permanently +reinstated, you do not qualify to receive new licenses for the same +material under section 10. + + 9. Acceptance Not Required for Having Copies. + + You are not required to accept this License in order to receive or +run a copy of the Program. Ancillary propagation of a covered work +occurring solely as a consequence of using peer-to-peer transmission +to receive a copy likewise does not require acceptance. However, +nothing other than this License grants you permission to propagate or +modify any covered work. These actions infringe copyright if you do +not accept this License. Therefore, by modifying or propagating a +covered work, you indicate your acceptance of this License to do so. + + 10. Automatic Licensing of Downstream Recipients. + + Each time you convey a covered work, the recipient automatically +receives a license from the original licensors, to run, modify and +propagate that work, subject to this License. You are not responsible +for enforcing compliance by third parties with this License. + + An "entity transaction" is a transaction transferring control of an +organization, or substantially all assets of one, or subdividing an +organization, or merging organizations. If propagation of a covered +work results from an entity transaction, each party to that +transaction who receives a copy of the work also receives whatever +licenses to the work the party's predecessor in interest had or could +give under the previous paragraph, plus a right to possession of the +Corresponding Source of the work from the predecessor in interest, if +the predecessor has it or can get it with reasonable efforts. + + You may not impose any further restrictions on the exercise of the +rights granted or affirmed under this License. For example, you may +not impose a license fee, royalty, or other charge for exercise of +rights granted under this License, and you may not initiate litigation +(including a cross-claim or counterclaim in a lawsuit) alleging that +any patent claim is infringed by making, using, selling, offering for +sale, or importing the Program or any portion of it. + + 11. Patents. + + A "contributor" is a copyright holder who authorizes use under this +License of the Program or a work on which the Program is based. The +work thus licensed is called the contributor's "contributor version". + + A contributor's "essential patent claims" are all patent claims +owned or controlled by the contributor, whether already acquired or +hereafter acquired, that would be infringed by some manner, permitted +by this License, of making, using, or selling its contributor version, +but do not include claims that would be infringed only as a +consequence of further modification of the contributor version. For +purposes of this definition, "control" includes the right to grant +patent sublicenses in a manner consistent with the requirements of +this License. + + Each contributor grants you a non-exclusive, worldwide, royalty-free +patent license under the contributor's essential patent claims, to +make, use, sell, offer for sale, import and otherwise run, modify and +propagate the contents of its contributor version. + + In the following three paragraphs, a "patent license" is any express +agreement or commitment, however denominated, not to enforce a patent +(such as an express permission to practice a patent or covenant not to +sue for patent infringement). To "grant" such a patent license to a +party means to make such an agreement or commitment not to enforce a +patent against the party. + + If you convey a covered work, knowingly relying on a patent license, +and the Corresponding Source of the work is not available for anyone +to copy, free of charge and under the terms of this License, through a +publicly available network server or other readily accessible means, +then you must either (1) cause the Corresponding Source to be so +available, or (2) arrange to deprive yourself of the benefit of the +patent license for this particular work, or (3) arrange, in a manner +consistent with the requirements of this License, to extend the patent +license to downstream recipients. "Knowingly relying" means you have +actual knowledge that, but for the patent license, your conveying the +covered work in a country, or your recipient's use of the covered work +in a country, would infringe one or more identifiable patents in that +country that you have reason to believe are valid. + + If, pursuant to or in connection with a single transaction or +arrangement, you convey, or propagate by procuring conveyance of, a +covered work, and grant a patent license to some of the parties +receiving the covered work authorizing them to use, propagate, modify +or convey a specific copy of the covered work, then the patent license +you grant is automatically extended to all recipients of the covered +work and works based on it. + + A patent license is "discriminatory" if it does not include within +the scope of its coverage, prohibits the exercise of, or is +conditioned on the non-exercise of one or more of the rights that are +specifically granted under this License. You may not convey a covered +work if you are a party to an arrangement with a third party that is +in the business of distributing software, under which you make payment +to the third party based on the extent of your activity of conveying +the work, and under which the third party grants, to any of the +parties who would receive the covered work from you, a discriminatory +patent license (a) in connection with copies of the covered work +conveyed by you (or copies made from those copies), or (b) primarily +for and in connection with specific products or compilations that +contain the covered work, unless you entered into that arrangement, +or that patent license was granted, prior to 28 March 2007. + + Nothing in this License shall be construed as excluding or limiting +any implied license or other defenses to infringement that may +otherwise be available to you under applicable patent law. + + 12. No Surrender of Others' Freedom. + + If conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot convey a +covered work so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you may +not convey it at all. For example, if you agree to terms that obligate you +to collect a royalty for further conveying from those to whom you convey +the Program, the only way you could satisfy both those terms and this +License would be to refrain entirely from conveying the Program. + + 13. Remote Network Interaction; Use with the GNU General Public License. + + Notwithstanding any other provision of this License, if you modify the +Program, your modified version must prominently offer all users +interacting with it remotely through a computer network (if your version +supports such interaction) an opportunity to receive the Corresponding +Source of your version by providing access to the Corresponding Source +from a network server at no charge, through some standard or customary +means of facilitating copying of software. This Corresponding Source +shall include the Corresponding Source for any work covered by version 3 +of the GNU General Public License that is incorporated pursuant to the +following paragraph. + + Notwithstanding any other provision of this License, you have +permission to link or combine any covered work with a work licensed +under version 3 of the GNU General Public License into a single +combined work, and to convey the resulting work. The terms of this +License will continue to apply to the part which is the covered work, +but the work with which it is combined will remain governed by version +3 of the GNU General Public License. + + 14. Revised Versions of this License. + + The Free Software Foundation may publish revised and/or new versions of +the GNU Affero General Public License from time to time. Such new versions +will be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + + Each version is given a distinguishing version number. If the +Program specifies that a certain numbered version of the GNU Affero General +Public License "or any later version" applies to it, you have the +option of following the terms and conditions either of that numbered +version or of any later version published by the Free Software +Foundation. If the Program does not specify a version number of the +GNU Affero General Public License, you may choose any version ever published +by the Free Software Foundation. + + If the Program specifies that a proxy can decide which future +versions of the GNU Affero General Public License can be used, that proxy's +public statement of acceptance of a version permanently authorizes you +to choose that version for the Program. + + Later license versions may give you additional or different +permissions. However, no additional obligations are imposed on any +author or copyright holder as a result of your choosing to follow a +later version. + + 15. Disclaimer of Warranty. + + THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY +APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT +HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY +OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM +IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF +ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. Limitation of Liability. + + IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS +THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY +GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE +USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF +DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD +PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), +EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF +SUCH DAMAGES. + + 17. Interpretation of Sections 15 and 16. + + If the disclaimer of warranty and limitation of liability provided +above cannot be given local legal effect according to their terms, +reviewing courts shall apply local law that most closely approximates +an absolute waiver of all civil liability in connection with the +Program, unless a warranty or assumption of liability accompanies a +copy of the Program in return for a fee. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +state the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Affero General Public License as published + by the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see . + +Also add information on how to contact you by electronic and paper mail. + + If your software can interact with users remotely through a computer +network, you should also make sure that it provides a way for users to +get its source. For example, if your program is a web application, its +interface could display a "Source" link that leads users to an archive +of the code. There are many ways you could offer source, and different +solutions will be better for different programs; see section 13 for the +specific requirements. + + You should also get your employer (if you work as a programmer) or school, +if any, to sign a "copyright disclaimer" for the program, if necessary. +For more information on this, and how to apply and follow the GNU AGPL, see +. diff --git a/node_modules/asyncconsole/README.md b/node_modules/asyncconsole/README.md new file mode 100644 index 0000000..72a26ca --- /dev/null +++ b/node_modules/asyncconsole/README.md @@ -0,0 +1,14 @@ +# AsyncConsole +Async console for console commands. Works for all devices + +## Usage +> npm install asyncconsole + + +``` +var AsyncConsole = require('asyncconsole') +var console = new AsyncConsole(">", function(input) { +// do something with the input +}) + +``` diff --git a/node_modules/asyncconsole/index.js b/node_modules/asyncconsole/index.js new file mode 100644 index 0000000..859cfd8 --- /dev/null +++ b/node_modules/asyncconsole/index.js @@ -0,0 +1,189 @@ +"use strict" +/* + AsyncConsole - Simple async console command helper + Copyright (C) 2016 Andrew S + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Affero General Public License as published + by the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Affero General Public License for more details. + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see . +*/ +var EOL = require('os').EOL +module.exports = class AsyncConsole { +constructor(prompt, call,test,exit) { + this.call = call; + this.exit = exit; + this.prompt = prompt; +this.stdin = process.stdin; + this.test = test; +this.stdin.setRawMode(true); +this.stdin.resume(); + this.paused = false; +this.stdin.setEncoding('utf8'); + this.stdin.on('data',function(key) { + if (key == '\u0003') { + if (this.exit) this.exit(0); else process.exit(0); + } +this.onKey(key) + + }.bind(this)) + this.text = []; + this.console = []; + this.cursor = { + x: 0, + y: 0 + + } + this.constants = { + UP: "\u001B\u005B\u0041", + DOWN: "\u001B\u005B\u0042", + LEFT: "\u001B\u005B\u0044", + RIGHT: "\u001B\u005B\u0043", + ENTER: "\u000D", + BACK1: "\u0008", + BACK2: "\u007F" + } + + this.log(this.prompt) +} + +onKey(key) { + if (this.paused || (this.test && !this.test(key))) return; + switch (key) { + case '\u000D': // enter + this.enter() + break; + case '\u007F': // back. (mac) + this.back() + break; + case '\u0008': // back. (win) + this.back() + break; + case '\u001B\u005B\u0041': // up + this.up() + break; + case '\u001B\u005B\u0042': // down + this.down() + break; + case '\u001B\u005B\u0044': // left + this.left() + break; + case '\u001B\u005B\u0043': // right + this.right() + break; + default: + this.key(key) + break; + + } + + +} + pause() { + this.paused = true; + this.stdin.pause() + } + resume() { + this.paused = false; + this.stdin.resume() + } + escape(a) { + var allowed = "` 1 2 3 4 5 6 7 8 9 0 - = q w e r t y u i o p [ ] | a s d f g h j k l ; ' z x c v b n m , . / ~ ! @ # $ % ^ & * ( ) _ + Q W E R T Y U I O P { } A S D F G H J K L : \\ \" Z X C V B N M < > ?" + var allow = allowed.split(" "); + if (a == " ") return true; + if (allow.indexOf(a) == -1) return false; + return true; + } + fill(a,num,char) { + a = a || "" + char = char || " " + num = num || (process.stdout.columns - 1) + num -= a.length + for (var i = 0; i < num; i ++) { + a += char + } + return a + + } + log(a) { +if (this.paused) return; + process.stdout.write(a) + } + clearLine() { + this.log(this.fill('\r')) + } + enter() { + this.log(EOL) + + if (this.text.length != 0) { + var text = this.text.join("") + this.console.push(this.text) + this.cursor.y = this.console.length + this.cursor.x = 0; + this.text = []; + this.call(text) + } + this.log(this.prompt) + } + back() { + if (this.text.length == 0) return; + + if (this.cursor.x > 0) { + this.text.splice(this.cursor.x-1,1) + this.cursor.x -- + } + this.log(this.fill('\r'+this.prompt + this.text.join(""))) + this.sendOrig() + } + + up() { + if (this.cursor.y > 0) this.cursor.y --; + this.text = this.console[this.cursor.y] || [] + this.cursor.x = this.text.length + this.log(this.fill("\r"+this.prompt + this.text.join(""))) + this.sendOrig() + } + down() { + if (this.cursor.y < this.console.length) this.cursor.y ++; + this.text = this.console[this.cursor.y] || [] + this.cursor.x = this.text.length + this.log(this.fill("\r"+this.prompt + this.text.join(""))) + this.sendOrig() + } + left() { + if (this.cursor.x > 0) { + this.cursor.x --; + this.log('\x1b[1D') + } + } + right() { + if (this.cursor.x < this.text.length) { + this.cursor.x ++; + this.log('\x1b[1C') + } + } + key(key) { + if (!this.escape(key)) return; + + this.text.splice(this.cursor.x,0,key) + this.cursor.x ++; + this.log(this.fill("\r"+this.prompt + this.text.join(""))) + + this.sendOrig() + } + sendOrig() { + var amount = process.stdout.columns - this.cursor.x - 3 - (this.prompt.split("").length) + 1; + this.log(eval('\'\\x1b[' + amount + 'D\'')) + + + } +onEnter(t) { + + +} +} diff --git a/node_modules/asyncconsole/package.json b/node_modules/asyncconsole/package.json new file mode 100644 index 0000000..6609356 --- /dev/null +++ b/node_modules/asyncconsole/package.json @@ -0,0 +1,23 @@ +{ + "name": "asyncconsole", + "version": "1.3.9", + "description": "Async console", + "main": "index.js", + "scripts": { + "test": "node test.js" + }, + "repository": { + "type": "git", + "url": "git+https://github.com/AJS-development/AsyncConsole.git" + }, + "keywords": [ + "console", + "async" + ], + "author": "Andrews54757", + "license": "AGPL-3.0", + "bugs": { + "url": "https://github.com/AJS-development/AsyncConsole/issues" + }, + "homepage": "https://github.com/AJS-development/AsyncConsole#readme" +} diff --git a/node_modules/asyncconsole/test.js b/node_modules/asyncconsole/test.js new file mode 100644 index 0000000..a55e9d4 --- /dev/null +++ b/node_modules/asyncconsole/test.js @@ -0,0 +1,5 @@ +var a = require('./index.js') +var b = new a(' > ', function(data) { +console.log("Your input: " + data) + +}) diff --git a/node_modules/bindings/LICENSE.md b/node_modules/bindings/LICENSE.md new file mode 100644 index 0000000..5a92289 --- /dev/null +++ b/node_modules/bindings/LICENSE.md @@ -0,0 +1,22 @@ +(The MIT License) + +Copyright (c) 2012 Nathan Rajlich <nathan@tootallnate.net> + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +'Software'), to deal 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: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +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. diff --git a/node_modules/bindings/README.md b/node_modules/bindings/README.md new file mode 100644 index 0000000..5b3e7a8 --- /dev/null +++ b/node_modules/bindings/README.md @@ -0,0 +1,98 @@ +node-bindings +============= +### Helper module for loading your native module's `.node` file + +This is a helper module for authors of Node.js native addon modules. +It is basically the "swiss army knife" of `require()`ing your native module's +`.node` file. + +Throughout the course of Node's native addon history, addons have ended up being +compiled in a variety of different places, depending on which build tool and which +version of node was used. To make matters worse, now the `gyp` build tool can +produce either a __Release__ or __Debug__ build, each being built into different +locations. + +This module checks _all_ the possible locations that a native addon would be built +at, and returns the first one that loads successfully. + + +Installation +------------ + +Install with `npm`: + +``` bash +$ npm install --save bindings +``` + +Or add it to the `"dependencies"` section of your `package.json` file. + + +Example +------- + +`require()`ing the proper bindings file for the current node version, platform +and architecture is as simple as: + +``` js +var bindings = require('bindings')('binding.node') + +// Use your bindings defined in your C files +bindings.your_c_function() +``` + + +Nice Error Output +----------------- + +When the `.node` file could not be loaded, `node-bindings` throws an Error with +a nice error message telling you exactly what was tried. You can also check the +`err.tries` Array property. + +``` +Error: Could not load the bindings file. Tried: + → /Users/nrajlich/ref/build/binding.node + → /Users/nrajlich/ref/build/Debug/binding.node + → /Users/nrajlich/ref/build/Release/binding.node + → /Users/nrajlich/ref/out/Debug/binding.node + → /Users/nrajlich/ref/Debug/binding.node + → /Users/nrajlich/ref/out/Release/binding.node + → /Users/nrajlich/ref/Release/binding.node + → /Users/nrajlich/ref/build/default/binding.node + → /Users/nrajlich/ref/compiled/0.8.2/darwin/x64/binding.node + at bindings (/Users/nrajlich/ref/node_modules/bindings/bindings.js:84:13) + at Object. (/Users/nrajlich/ref/lib/ref.js:5:47) + at Module._compile (module.js:449:26) + at Object.Module._extensions..js (module.js:467:10) + at Module.load (module.js:356:32) + at Function.Module._load (module.js:312:12) + ... +``` + +The searching for the `.node` file will originate from the first directory in which has a `package.json` file is found. + +License +------- + +(The MIT License) + +Copyright (c) 2012 Nathan Rajlich <nathan@tootallnate.net> + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +'Software'), to deal 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: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +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. diff --git a/node_modules/bindings/bindings.js b/node_modules/bindings/bindings.js new file mode 100644 index 0000000..727413a --- /dev/null +++ b/node_modules/bindings/bindings.js @@ -0,0 +1,221 @@ +/** + * Module dependencies. + */ + +var fs = require('fs'), + path = require('path'), + fileURLToPath = require('file-uri-to-path'), + join = path.join, + dirname = path.dirname, + exists = + (fs.accessSync && + function(path) { + try { + fs.accessSync(path); + } catch (e) { + return false; + } + return true; + }) || + fs.existsSync || + path.existsSync, + defaults = { + arrow: process.env.NODE_BINDINGS_ARROW || ' → ', + compiled: process.env.NODE_BINDINGS_COMPILED_DIR || 'compiled', + platform: process.platform, + arch: process.arch, + nodePreGyp: + 'node-v' + + process.versions.modules + + '-' + + process.platform + + '-' + + process.arch, + version: process.versions.node, + bindings: 'bindings.node', + try: [ + // node-gyp's linked version in the "build" dir + ['module_root', 'build', 'bindings'], + // node-waf and gyp_addon (a.k.a node-gyp) + ['module_root', 'build', 'Debug', 'bindings'], + ['module_root', 'build', 'Release', 'bindings'], + // Debug files, for development (legacy behavior, remove for node v0.9) + ['module_root', 'out', 'Debug', 'bindings'], + ['module_root', 'Debug', 'bindings'], + // Release files, but manually compiled (legacy behavior, remove for node v0.9) + ['module_root', 'out', 'Release', 'bindings'], + ['module_root', 'Release', 'bindings'], + // Legacy from node-waf, node <= 0.4.x + ['module_root', 'build', 'default', 'bindings'], + // Production "Release" buildtype binary (meh...) + ['module_root', 'compiled', 'version', 'platform', 'arch', 'bindings'], + // node-qbs builds + ['module_root', 'addon-build', 'release', 'install-root', 'bindings'], + ['module_root', 'addon-build', 'debug', 'install-root', 'bindings'], + ['module_root', 'addon-build', 'default', 'install-root', 'bindings'], + // node-pre-gyp path ./lib/binding/{node_abi}-{platform}-{arch} + ['module_root', 'lib', 'binding', 'nodePreGyp', 'bindings'] + ] + }; + +/** + * The main `bindings()` function loads the compiled bindings for a given module. + * It uses V8's Error API to determine the parent filename that this function is + * being invoked from, which is then used to find the root directory. + */ + +function bindings(opts) { + // Argument surgery + if (typeof opts == 'string') { + opts = { bindings: opts }; + } else if (!opts) { + opts = {}; + } + + // maps `defaults` onto `opts` object + Object.keys(defaults).map(function(i) { + if (!(i in opts)) opts[i] = defaults[i]; + }); + + // Get the module root + if (!opts.module_root) { + opts.module_root = exports.getRoot(exports.getFileName()); + } + + // Ensure the given bindings name ends with .node + if (path.extname(opts.bindings) != '.node') { + opts.bindings += '.node'; + } + + // https://github.com/webpack/webpack/issues/4175#issuecomment-342931035 + var requireFunc = + typeof __webpack_require__ === 'function' + ? __non_webpack_require__ + : require; + + var tries = [], + i = 0, + l = opts.try.length, + n, + b, + err; + + for (; i < l; i++) { + n = join.apply( + null, + opts.try[i].map(function(p) { + return opts[p] || p; + }) + ); + tries.push(n); + try { + b = opts.path ? requireFunc.resolve(n) : requireFunc(n); + if (!opts.path) { + b.path = n; + } + return b; + } catch (e) { + if (e.code !== 'MODULE_NOT_FOUND' && + e.code !== 'QUALIFIED_PATH_RESOLUTION_FAILED' && + !/not find/i.test(e.message)) { + throw e; + } + } + } + + err = new Error( + 'Could not locate the bindings file. Tried:\n' + + tries + .map(function(a) { + return opts.arrow + a; + }) + .join('\n') + ); + err.tries = tries; + throw err; +} +module.exports = exports = bindings; + +/** + * Gets the filename of the JavaScript file that invokes this function. + * Used to help find the root directory of a module. + * Optionally accepts an filename argument to skip when searching for the invoking filename + */ + +exports.getFileName = function getFileName(calling_file) { + var origPST = Error.prepareStackTrace, + origSTL = Error.stackTraceLimit, + dummy = {}, + fileName; + + Error.stackTraceLimit = 10; + + Error.prepareStackTrace = function(e, st) { + for (var i = 0, l = st.length; i < l; i++) { + fileName = st[i].getFileName(); + if (fileName !== __filename) { + if (calling_file) { + if (fileName !== calling_file) { + return; + } + } else { + return; + } + } + } + }; + + // run the 'prepareStackTrace' function above + Error.captureStackTrace(dummy); + dummy.stack; + + // cleanup + Error.prepareStackTrace = origPST; + Error.stackTraceLimit = origSTL; + + // handle filename that starts with "file://" + var fileSchema = 'file://'; + if (fileName.indexOf(fileSchema) === 0) { + fileName = fileURLToPath(fileName); + } + + return fileName; +}; + +/** + * Gets the root directory of a module, given an arbitrary filename + * somewhere in the module tree. The "root directory" is the directory + * containing the `package.json` file. + * + * In: /home/nate/node-native-module/lib/index.js + * Out: /home/nate/node-native-module + */ + +exports.getRoot = function getRoot(file) { + var dir = dirname(file), + prev; + while (true) { + if (dir === '.') { + // Avoids an infinite loop in rare cases, like the REPL + dir = process.cwd(); + } + if ( + exists(join(dir, 'package.json')) || + exists(join(dir, 'node_modules')) + ) { + // Found the 'package.json' file or 'node_modules' dir; we're done + return dir; + } + if (prev === dir) { + // Got to the top + throw new Error( + 'Could not find module root given file: "' + + file + + '". Do you have a `package.json` file? ' + ); + } + // Try the parent dir next + prev = dir; + dir = join(dir, '..'); + } +}; diff --git a/node_modules/bindings/package.json b/node_modules/bindings/package.json new file mode 100644 index 0000000..d027ee7 --- /dev/null +++ b/node_modules/bindings/package.json @@ -0,0 +1,28 @@ +{ + "name": "bindings", + "description": "Helper module for loading your native module's .node file", + "keywords": [ + "native", + "addon", + "bindings", + "gyp", + "waf", + "c", + "c++" + ], + "version": "1.5.0", + "author": "Nathan Rajlich (http://tootallnate.net)", + "repository": { + "type": "git", + "url": "git://github.com/TooTallNate/node-bindings.git" + }, + "main": "./bindings.js", + "bugs": { + "url": "https://github.com/TooTallNate/node-bindings/issues" + }, + "homepage": "https://github.com/TooTallNate/node-bindings", + "license": "MIT", + "dependencies": { + "file-uri-to-path": "1.0.0" + } +} diff --git a/node_modules/colors/LICENSE b/node_modules/colors/LICENSE new file mode 100644 index 0000000..17880ff --- /dev/null +++ b/node_modules/colors/LICENSE @@ -0,0 +1,25 @@ +MIT License + +Original Library + - Copyright (c) Marak Squires + +Additional Functionality + - Copyright (c) Sindre Sorhus (sindresorhus.com) + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +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: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +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. diff --git a/node_modules/colors/README.md b/node_modules/colors/README.md new file mode 100644 index 0000000..fabe558 --- /dev/null +++ b/node_modules/colors/README.md @@ -0,0 +1,221 @@ +# colors.js +[![Build Status](https://travis-ci.org/Marak/colors.js.svg?branch=master)](https://travis-ci.org/Marak/colors.js) +[![version](https://img.shields.io/npm/v/colors.svg)](https://www.npmjs.org/package/colors) +[![dependencies](https://david-dm.org/Marak/colors.js.svg)](https://david-dm.org/Marak/colors.js) +[![devDependencies](https://david-dm.org/Marak/colors.js/dev-status.svg)](https://david-dm.org/Marak/colors.js#info=devDependencies) + +Please check out the [roadmap](ROADMAP.md) for upcoming features and releases. Please open Issues to provide feedback, and check the `develop` branch for the latest bleeding-edge updates. + +## get color and style in your node.js console + +![Demo](https://raw.githubusercontent.com/Marak/colors.js/master/screenshots/colors.png) + +## Installation + + npm install colors + +## colors and styles! + +### text colors + + - black + - red + - green + - yellow + - blue + - magenta + - cyan + - white + - gray + - grey + +### bright text colors + + - brightRed + - brightGreen + - brightYellow + - brightBlue + - brightMagenta + - brightCyan + - brightWhite + +### background colors + + - bgBlack + - bgRed + - bgGreen + - bgYellow + - bgBlue + - bgMagenta + - bgCyan + - bgWhite + - bgGray + - bgGrey + +### bright background colors + + - bgBrightRed + - bgBrightGreen + - bgBrightYellow + - bgBrightBlue + - bgBrightMagenta + - bgBrightCyan + - bgBrightWhite + +### styles + + - reset + - bold + - dim + - italic + - underline + - inverse + - hidden + - strikethrough + +### extras + + - rainbow + - zebra + - america + - trap + - random + + +## Usage + +By popular demand, `colors` now ships with two types of usages! + +The super nifty way + +```js +var colors = require('colors'); + +console.log('hello'.green); // outputs green text +console.log('i like cake and pies'.underline.red) // outputs red underlined text +console.log('inverse the color'.inverse); // inverses the color +console.log('OMG Rainbows!'.rainbow); // rainbow +console.log('Run the trap'.trap); // Drops the bass + +``` + +or a slightly less nifty way which doesn't extend `String.prototype` + +```js +var colors = require('colors/safe'); + +console.log(colors.green('hello')); // outputs green text +console.log(colors.red.underline('i like cake and pies')) // outputs red underlined text +console.log(colors.inverse('inverse the color')); // inverses the color +console.log(colors.rainbow('OMG Rainbows!')); // rainbow +console.log(colors.trap('Run the trap')); // Drops the bass + +``` + +I prefer the first way. Some people seem to be afraid of extending `String.prototype` and prefer the second way. + +If you are writing good code you will never have an issue with the first approach. If you really don't want to touch `String.prototype`, the second usage will not touch `String` native object. + +## Enabling/Disabling Colors + +The package will auto-detect whether your terminal can use colors and enable/disable accordingly. When colors are disabled, the color functions do nothing. You can override this with a command-line flag: + +```bash +node myapp.js --no-color +node myapp.js --color=false + +node myapp.js --color +node myapp.js --color=true +node myapp.js --color=always + +FORCE_COLOR=1 node myapp.js +``` + +Or in code: + +```javascript +var colors = require('colors'); +colors.enable(); +colors.disable(); +``` + +## Console.log [string substitution](http://nodejs.org/docs/latest/api/console.html#console_console_log_data) + +```js +var name = 'Marak'; +console.log(colors.green('Hello %s'), name); +// outputs -> 'Hello Marak' +``` + +## Custom themes + +### Using standard API + +```js + +var colors = require('colors'); + +colors.setTheme({ + silly: 'rainbow', + input: 'grey', + verbose: 'cyan', + prompt: 'grey', + info: 'green', + data: 'grey', + help: 'cyan', + warn: 'yellow', + debug: 'blue', + error: 'red' +}); + +// outputs red text +console.log("this is an error".error); + +// outputs yellow text +console.log("this is a warning".warn); +``` + +### Using string safe API + +```js +var colors = require('colors/safe'); + +// set single property +var error = colors.red; +error('this is red'); + +// set theme +colors.setTheme({ + silly: 'rainbow', + input: 'grey', + verbose: 'cyan', + prompt: 'grey', + info: 'green', + data: 'grey', + help: 'cyan', + warn: 'yellow', + debug: 'blue', + error: 'red' +}); + +// outputs red text +console.log(colors.error("this is an error")); + +// outputs yellow text +console.log(colors.warn("this is a warning")); + +``` + +### Combining Colors + +```javascript +var colors = require('colors'); + +colors.setTheme({ + custom: ['red', 'underline'] +}); + +console.log('test'.custom); +``` + +*Protip: There is a secret undocumented style in `colors`. If you find the style you can summon him.* diff --git a/node_modules/colors/examples/normal-usage.js b/node_modules/colors/examples/normal-usage.js new file mode 100644 index 0000000..822db1c --- /dev/null +++ b/node_modules/colors/examples/normal-usage.js @@ -0,0 +1,82 @@ +var colors = require('../lib/index'); + +console.log('First some yellow text'.yellow); + +console.log('Underline that text'.yellow.underline); + +console.log('Make it bold and red'.red.bold); + +console.log(('Double Raindows All Day Long').rainbow); + +console.log('Drop the bass'.trap); + +console.log('DROP THE RAINBOW BASS'.trap.rainbow); + +// styles not widely supported +console.log('Chains are also cool.'.bold.italic.underline.red); + +// styles not widely supported +console.log('So '.green + 'are'.underline + ' ' + 'inverse'.inverse + + ' styles! '.yellow.bold); +console.log('Zebras are so fun!'.zebra); + +// +// Remark: .strikethrough may not work with Mac OS Terminal App +// +console.log('This is ' + 'not'.strikethrough + ' fun.'); + +console.log('Background color attack!'.black.bgWhite); +console.log('Use random styles on everything!'.random); +console.log('America, Heck Yeah!'.america); + +console.log('Blindingly '.brightCyan + 'bright? '.brightRed + 'Why '.brightYellow + 'not?!'.brightGreen); + +console.log('Setting themes is useful'); + +// +// Custom themes +// +console.log('Generic logging theme as JSON'.green.bold.underline); +// Load theme with JSON literal +colors.setTheme({ + silly: 'rainbow', + input: 'grey', + verbose: 'cyan', + prompt: 'grey', + info: 'green', + data: 'grey', + help: 'cyan', + warn: 'yellow', + debug: 'blue', + error: 'red', +}); + +// outputs red text +console.log('this is an error'.error); + +// outputs yellow text +console.log('this is a warning'.warn); + +// outputs grey text +console.log('this is an input'.input); + +console.log('Generic logging theme as file'.green.bold.underline); + +// Load a theme from file +try { + colors.setTheme(require(__dirname + '/../themes/generic-logging.js')); +} catch (err) { + console.log(err); +} + +// outputs red text +console.log('this is an error'.error); + +// outputs yellow text +console.log('this is a warning'.warn); + +// outputs grey text +console.log('this is an input'.input); + +// console.log("Don't summon".zalgo) + diff --git a/node_modules/colors/examples/safe-string.js b/node_modules/colors/examples/safe-string.js new file mode 100644 index 0000000..5bc0168 --- /dev/null +++ b/node_modules/colors/examples/safe-string.js @@ -0,0 +1,79 @@ +var colors = require('../safe'); + +console.log(colors.yellow('First some yellow text')); + +console.log(colors.yellow.underline('Underline that text')); + +console.log(colors.red.bold('Make it bold and red')); + +console.log(colors.rainbow('Double Raindows All Day Long')); + +console.log(colors.trap('Drop the bass')); + +console.log(colors.rainbow(colors.trap('DROP THE RAINBOW BASS'))); + +// styles not widely supported +console.log(colors.bold.italic.underline.red('Chains are also cool.')); + +// styles not widely supported +console.log(colors.green('So ') + colors.underline('are') + ' ' + + colors.inverse('inverse') + colors.yellow.bold(' styles! ')); + +console.log(colors.zebra('Zebras are so fun!')); + +console.log('This is ' + colors.strikethrough('not') + ' fun.'); + + +console.log(colors.black.bgWhite('Background color attack!')); +console.log(colors.random('Use random styles on everything!')); +console.log(colors.america('America, Heck Yeah!')); + +console.log(colors.brightCyan('Blindingly ') + colors.brightRed('bright? ') + colors.brightYellow('Why ') + colors.brightGreen('not?!')); + +console.log('Setting themes is useful'); + +// +// Custom themes +// +// console.log('Generic logging theme as JSON'.green.bold.underline); +// Load theme with JSON literal +colors.setTheme({ + silly: 'rainbow', + input: 'blue', + verbose: 'cyan', + prompt: 'grey', + info: 'green', + data: 'grey', + help: 'cyan', + warn: 'yellow', + debug: 'blue', + error: 'red', +}); + +// outputs red text +console.log(colors.error('this is an error')); + +// outputs yellow text +console.log(colors.warn('this is a warning')); + +// outputs blue text +console.log(colors.input('this is an input')); + + +// console.log('Generic logging theme as file'.green.bold.underline); + +// Load a theme from file +colors.setTheme(require(__dirname + '/../themes/generic-logging.js')); + +// outputs red text +console.log(colors.error('this is an error')); + +// outputs yellow text +console.log(colors.warn('this is a warning')); + +// outputs grey text +console.log(colors.input('this is an input')); + +// console.log(colors.zalgo("Don't summon him")) + + diff --git a/node_modules/colors/index.d.ts b/node_modules/colors/index.d.ts new file mode 100644 index 0000000..baa7068 --- /dev/null +++ b/node_modules/colors/index.d.ts @@ -0,0 +1,136 @@ +// Type definitions for Colors.js 1.2 +// Project: https://github.com/Marak/colors.js +// Definitions by: Bart van der Schoor , Staffan Eketorp +// Definitions: https://github.com/Marak/colors.js + +export interface Color { + (text: string): string; + + strip: Color; + stripColors: Color; + + black: Color; + red: Color; + green: Color; + yellow: Color; + blue: Color; + magenta: Color; + cyan: Color; + white: Color; + gray: Color; + grey: Color; + + bgBlack: Color; + bgRed: Color; + bgGreen: Color; + bgYellow: Color; + bgBlue: Color; + bgMagenta: Color; + bgCyan: Color; + bgWhite: Color; + + reset: Color; + bold: Color; + dim: Color; + italic: Color; + underline: Color; + inverse: Color; + hidden: Color; + strikethrough: Color; + + rainbow: Color; + zebra: Color; + america: Color; + trap: Color; + random: Color; + zalgo: Color; +} + +export function enable(): void; +export function disable(): void; +export function setTheme(theme: any): void; + +export let enabled: boolean; + +export const strip: Color; +export const stripColors: Color; + +export const black: Color; +export const red: Color; +export const green: Color; +export const yellow: Color; +export const blue: Color; +export const magenta: Color; +export const cyan: Color; +export const white: Color; +export const gray: Color; +export const grey: Color; + +export const bgBlack: Color; +export const bgRed: Color; +export const bgGreen: Color; +export const bgYellow: Color; +export const bgBlue: Color; +export const bgMagenta: Color; +export const bgCyan: Color; +export const bgWhite: Color; + +export const reset: Color; +export const bold: Color; +export const dim: Color; +export const italic: Color; +export const underline: Color; +export const inverse: Color; +export const hidden: Color; +export const strikethrough: Color; + +export const rainbow: Color; +export const zebra: Color; +export const america: Color; +export const trap: Color; +export const random: Color; +export const zalgo: Color; + +declare global { + interface String { + strip: string; + stripColors: string; + + black: string; + red: string; + green: string; + yellow: string; + blue: string; + magenta: string; + cyan: string; + white: string; + gray: string; + grey: string; + + bgBlack: string; + bgRed: string; + bgGreen: string; + bgYellow: string; + bgBlue: string; + bgMagenta: string; + bgCyan: string; + bgWhite: string; + + reset: string; + // @ts-ignore + bold: string; + dim: string; + italic: string; + underline: string; + inverse: string; + hidden: string; + strikethrough: string; + + rainbow: string; + zebra: string; + america: string; + trap: string; + random: string; + zalgo: string; + } +} diff --git a/node_modules/colors/lib/colors.js b/node_modules/colors/lib/colors.js new file mode 100644 index 0000000..9c7f1d1 --- /dev/null +++ b/node_modules/colors/lib/colors.js @@ -0,0 +1,211 @@ +/* + +The MIT License (MIT) + +Original Library + - Copyright (c) Marak Squires + +Additional functionality + - Copyright (c) Sindre Sorhus (sindresorhus.com) + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +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: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +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. + +*/ + +var colors = {}; +module['exports'] = colors; + +colors.themes = {}; + +var util = require('util'); +var ansiStyles = colors.styles = require('./styles'); +var defineProps = Object.defineProperties; +var newLineRegex = new RegExp(/[\r\n]+/g); + +colors.supportsColor = require('./system/supports-colors').supportsColor; + +if (typeof colors.enabled === 'undefined') { + colors.enabled = colors.supportsColor() !== false; +} + +colors.enable = function() { + colors.enabled = true; +}; + +colors.disable = function() { + colors.enabled = false; +}; + +colors.stripColors = colors.strip = function(str) { + return ('' + str).replace(/\x1B\[\d+m/g, ''); +}; + +// eslint-disable-next-line no-unused-vars +var stylize = colors.stylize = function stylize(str, style) { + if (!colors.enabled) { + return str+''; + } + + var styleMap = ansiStyles[style]; + + // Stylize should work for non-ANSI styles, too + if(!styleMap && style in colors){ + // Style maps like trap operate as functions on strings; + // they don't have properties like open or close. + return colors[style](str); + } + + return styleMap.open + str + styleMap.close; +}; + +var matchOperatorsRe = /[|\\{}()[\]^$+*?.]/g; +var escapeStringRegexp = function(str) { + if (typeof str !== 'string') { + throw new TypeError('Expected a string'); + } + return str.replace(matchOperatorsRe, '\\$&'); +}; + +function build(_styles) { + var builder = function builder() { + return applyStyle.apply(builder, arguments); + }; + builder._styles = _styles; + // __proto__ is used because we must return a function, but there is + // no way to create a function with a different prototype. + builder.__proto__ = proto; + return builder; +} + +var styles = (function() { + var ret = {}; + ansiStyles.grey = ansiStyles.gray; + Object.keys(ansiStyles).forEach(function(key) { + ansiStyles[key].closeRe = + new RegExp(escapeStringRegexp(ansiStyles[key].close), 'g'); + ret[key] = { + get: function() { + return build(this._styles.concat(key)); + }, + }; + }); + return ret; +})(); + +var proto = defineProps(function colors() {}, styles); + +function applyStyle() { + var args = Array.prototype.slice.call(arguments); + + var str = args.map(function(arg) { + // Use weak equality check so we can colorize null/undefined in safe mode + if (arg != null && arg.constructor === String) { + return arg; + } else { + return util.inspect(arg); + } + }).join(' '); + + if (!colors.enabled || !str) { + return str; + } + + var newLinesPresent = str.indexOf('\n') != -1; + + var nestedStyles = this._styles; + + var i = nestedStyles.length; + while (i--) { + var code = ansiStyles[nestedStyles[i]]; + str = code.open + str.replace(code.closeRe, code.open) + code.close; + if (newLinesPresent) { + str = str.replace(newLineRegex, function(match) { + return code.close + match + code.open; + }); + } + } + + return str; +} + +colors.setTheme = function(theme) { + if (typeof theme === 'string') { + console.log('colors.setTheme now only accepts an object, not a string. ' + + 'If you are trying to set a theme from a file, it is now your (the ' + + 'caller\'s) responsibility to require the file. The old syntax ' + + 'looked like colors.setTheme(__dirname + ' + + '\'/../themes/generic-logging.js\'); The new syntax looks like '+ + 'colors.setTheme(require(__dirname + ' + + '\'/../themes/generic-logging.js\'));'); + return; + } + for (var style in theme) { + (function(style) { + colors[style] = function(str) { + if (typeof theme[style] === 'object') { + var out = str; + for (var i in theme[style]) { + out = colors[theme[style][i]](out); + } + return out; + } + return colors[theme[style]](str); + }; + })(style); + } +}; + +function init() { + var ret = {}; + Object.keys(styles).forEach(function(name) { + ret[name] = { + get: function() { + return build([name]); + }, + }; + }); + return ret; +} + +var sequencer = function sequencer(map, str) { + var exploded = str.split(''); + exploded = exploded.map(map); + return exploded.join(''); +}; + +// custom formatter methods +colors.trap = require('./custom/trap'); +colors.zalgo = require('./custom/zalgo'); + +// maps +colors.maps = {}; +colors.maps.america = require('./maps/america')(colors); +colors.maps.zebra = require('./maps/zebra')(colors); +colors.maps.rainbow = require('./maps/rainbow')(colors); +colors.maps.random = require('./maps/random')(colors); + +for (var map in colors.maps) { + (function(map) { + colors[map] = function(str) { + return sequencer(colors.maps[map], str); + }; + })(map); +} + +defineProps(colors, init()); diff --git a/node_modules/colors/lib/custom/trap.js b/node_modules/colors/lib/custom/trap.js new file mode 100644 index 0000000..fbccf88 --- /dev/null +++ b/node_modules/colors/lib/custom/trap.js @@ -0,0 +1,46 @@ +module['exports'] = function runTheTrap(text, options) { + var result = ''; + text = text || 'Run the trap, drop the bass'; + text = text.split(''); + var trap = { + a: ['\u0040', '\u0104', '\u023a', '\u0245', '\u0394', '\u039b', '\u0414'], + b: ['\u00df', '\u0181', '\u0243', '\u026e', '\u03b2', '\u0e3f'], + c: ['\u00a9', '\u023b', '\u03fe'], + d: ['\u00d0', '\u018a', '\u0500', '\u0501', '\u0502', '\u0503'], + e: ['\u00cb', '\u0115', '\u018e', '\u0258', '\u03a3', '\u03be', '\u04bc', + '\u0a6c'], + f: ['\u04fa'], + g: ['\u0262'], + h: ['\u0126', '\u0195', '\u04a2', '\u04ba', '\u04c7', '\u050a'], + i: ['\u0f0f'], + j: ['\u0134'], + k: ['\u0138', '\u04a0', '\u04c3', '\u051e'], + l: ['\u0139'], + m: ['\u028d', '\u04cd', '\u04ce', '\u0520', '\u0521', '\u0d69'], + n: ['\u00d1', '\u014b', '\u019d', '\u0376', '\u03a0', '\u048a'], + o: ['\u00d8', '\u00f5', '\u00f8', '\u01fe', '\u0298', '\u047a', '\u05dd', + '\u06dd', '\u0e4f'], + p: ['\u01f7', '\u048e'], + q: ['\u09cd'], + r: ['\u00ae', '\u01a6', '\u0210', '\u024c', '\u0280', '\u042f'], + s: ['\u00a7', '\u03de', '\u03df', '\u03e8'], + t: ['\u0141', '\u0166', '\u0373'], + u: ['\u01b1', '\u054d'], + v: ['\u05d8'], + w: ['\u0428', '\u0460', '\u047c', '\u0d70'], + x: ['\u04b2', '\u04fe', '\u04fc', '\u04fd'], + y: ['\u00a5', '\u04b0', '\u04cb'], + z: ['\u01b5', '\u0240'], + }; + text.forEach(function(c) { + c = c.toLowerCase(); + var chars = trap[c] || [' ']; + var rand = Math.floor(Math.random() * chars.length); + if (typeof trap[c] !== 'undefined') { + result += trap[c][rand]; + } else { + result += c; + } + }); + return result; +}; diff --git a/node_modules/colors/lib/custom/zalgo.js b/node_modules/colors/lib/custom/zalgo.js new file mode 100644 index 0000000..0ef2b01 --- /dev/null +++ b/node_modules/colors/lib/custom/zalgo.js @@ -0,0 +1,110 @@ +// please no +module['exports'] = function zalgo(text, options) { + text = text || ' he is here '; + var soul = { + 'up': [ + '̍', '̎', '̄', '̅', + '̿', '̑', '̆', '̐', + '͒', '͗', '͑', '̇', + '̈', '̊', '͂', '̓', + '̈', '͊', '͋', '͌', + '̃', '̂', '̌', '͐', + '̀', '́', '̋', '̏', + '̒', '̓', '̔', '̽', + '̉', 'ͣ', 'ͤ', 'ͥ', + 'ͦ', 'ͧ', 'ͨ', 'ͩ', + 'ͪ', 'ͫ', 'ͬ', 'ͭ', + 'ͮ', 'ͯ', '̾', '͛', + '͆', '̚', + ], + 'down': [ + '̖', '̗', '̘', '̙', + '̜', '̝', '̞', '̟', + '̠', '̤', '̥', '̦', + '̩', '̪', '̫', '̬', + '̭', '̮', '̯', '̰', + '̱', '̲', '̳', '̹', + '̺', '̻', '̼', 'ͅ', + '͇', '͈', '͉', '͍', + '͎', '͓', '͔', '͕', + '͖', '͙', '͚', '̣', + ], + 'mid': [ + '̕', '̛', '̀', '́', + '͘', '̡', '̢', '̧', + '̨', '̴', '̵', '̶', + '͜', '͝', '͞', + '͟', '͠', '͢', '̸', + '̷', '͡', ' ҉', + ], + }; + var all = [].concat(soul.up, soul.down, soul.mid); + + function randomNumber(range) { + var r = Math.floor(Math.random() * range); + return r; + } + + function isChar(character) { + var bool = false; + all.filter(function(i) { + bool = (i === character); + }); + return bool; + } + + + function heComes(text, options) { + var result = ''; + var counts; + var l; + options = options || {}; + options['up'] = + typeof options['up'] !== 'undefined' ? options['up'] : true; + options['mid'] = + typeof options['mid'] !== 'undefined' ? options['mid'] : true; + options['down'] = + typeof options['down'] !== 'undefined' ? options['down'] : true; + options['size'] = + typeof options['size'] !== 'undefined' ? options['size'] : 'maxi'; + text = text.split(''); + for (l in text) { + if (isChar(l)) { + continue; + } + result = result + text[l]; + counts = {'up': 0, 'down': 0, 'mid': 0}; + switch (options.size) { + case 'mini': + counts.up = randomNumber(8); + counts.mid = randomNumber(2); + counts.down = randomNumber(8); + break; + case 'maxi': + counts.up = randomNumber(16) + 3; + counts.mid = randomNumber(4) + 1; + counts.down = randomNumber(64) + 3; + break; + default: + counts.up = randomNumber(8) + 1; + counts.mid = randomNumber(6) / 2; + counts.down = randomNumber(8) + 1; + break; + } + + var arr = ['up', 'mid', 'down']; + for (var d in arr) { + var index = arr[d]; + for (var i = 0; i <= counts[index]; i++) { + if (options[index]) { + result = result + soul[index][randomNumber(soul[index].length)]; + } + } + } + } + return result; + } + // don't summon him + return heComes(text, options); +}; + diff --git a/node_modules/colors/lib/extendStringPrototype.js b/node_modules/colors/lib/extendStringPrototype.js new file mode 100644 index 0000000..46fd386 --- /dev/null +++ b/node_modules/colors/lib/extendStringPrototype.js @@ -0,0 +1,110 @@ +var colors = require('./colors'); + +module['exports'] = function() { + // + // Extends prototype of native string object to allow for "foo".red syntax + // + var addProperty = function(color, func) { + String.prototype.__defineGetter__(color, func); + }; + + addProperty('strip', function() { + return colors.strip(this); + }); + + addProperty('stripColors', function() { + return colors.strip(this); + }); + + addProperty('trap', function() { + return colors.trap(this); + }); + + addProperty('zalgo', function() { + return colors.zalgo(this); + }); + + addProperty('zebra', function() { + return colors.zebra(this); + }); + + addProperty('rainbow', function() { + return colors.rainbow(this); + }); + + addProperty('random', function() { + return colors.random(this); + }); + + addProperty('america', function() { + return colors.america(this); + }); + + // + // Iterate through all default styles and colors + // + var x = Object.keys(colors.styles); + x.forEach(function(style) { + addProperty(style, function() { + return colors.stylize(this, style); + }); + }); + + function applyTheme(theme) { + // + // Remark: This is a list of methods that exist + // on String that you should not overwrite. + // + var stringPrototypeBlacklist = [ + '__defineGetter__', '__defineSetter__', '__lookupGetter__', + '__lookupSetter__', 'charAt', 'constructor', 'hasOwnProperty', + 'isPrototypeOf', 'propertyIsEnumerable', 'toLocaleString', 'toString', + 'valueOf', 'charCodeAt', 'indexOf', 'lastIndexOf', 'length', + 'localeCompare', 'match', 'repeat', 'replace', 'search', 'slice', + 'split', 'substring', 'toLocaleLowerCase', 'toLocaleUpperCase', + 'toLowerCase', 'toUpperCase', 'trim', 'trimLeft', 'trimRight', + ]; + + Object.keys(theme).forEach(function(prop) { + if (stringPrototypeBlacklist.indexOf(prop) !== -1) { + console.log('warn: '.red + ('String.prototype' + prop).magenta + + ' is probably something you don\'t want to override. ' + + 'Ignoring style name'); + } else { + if (typeof(theme[prop]) === 'string') { + colors[prop] = colors[theme[prop]]; + addProperty(prop, function() { + return colors[prop](this); + }); + } else { + var themePropApplicator = function(str) { + var ret = str || this; + for (var t = 0; t < theme[prop].length; t++) { + ret = colors[theme[prop][t]](ret); + } + return ret; + }; + addProperty(prop, themePropApplicator); + colors[prop] = function(str) { + return themePropApplicator(str); + }; + } + } + }); + } + + colors.setTheme = function(theme) { + if (typeof theme === 'string') { + console.log('colors.setTheme now only accepts an object, not a string. ' + + 'If you are trying to set a theme from a file, it is now your (the ' + + 'caller\'s) responsibility to require the file. The old syntax ' + + 'looked like colors.setTheme(__dirname + ' + + '\'/../themes/generic-logging.js\'); The new syntax looks like '+ + 'colors.setTheme(require(__dirname + ' + + '\'/../themes/generic-logging.js\'));'); + return; + } else { + applyTheme(theme); + } + }; +}; diff --git a/node_modules/colors/lib/index.js b/node_modules/colors/lib/index.js new file mode 100644 index 0000000..9df5ab7 --- /dev/null +++ b/node_modules/colors/lib/index.js @@ -0,0 +1,13 @@ +var colors = require('./colors'); +module['exports'] = colors; + +// Remark: By default, colors will add style properties to String.prototype. +// +// If you don't wish to extend String.prototype, you can do this instead and +// native String will not be touched: +// +// var colors = require('colors/safe); +// colors.red("foo") +// +// +require('./extendStringPrototype')(); diff --git a/node_modules/colors/lib/maps/america.js b/node_modules/colors/lib/maps/america.js new file mode 100644 index 0000000..dc96903 --- /dev/null +++ b/node_modules/colors/lib/maps/america.js @@ -0,0 +1,10 @@ +module['exports'] = function(colors) { + return function(letter, i, exploded) { + if (letter === ' ') return letter; + switch (i%3) { + case 0: return colors.red(letter); + case 1: return colors.white(letter); + case 2: return colors.blue(letter); + } + }; +}; diff --git a/node_modules/colors/lib/maps/rainbow.js b/node_modules/colors/lib/maps/rainbow.js new file mode 100644 index 0000000..2b00ac0 --- /dev/null +++ b/node_modules/colors/lib/maps/rainbow.js @@ -0,0 +1,12 @@ +module['exports'] = function(colors) { + // RoY G BiV + var rainbowColors = ['red', 'yellow', 'green', 'blue', 'magenta']; + return function(letter, i, exploded) { + if (letter === ' ') { + return letter; + } else { + return colors[rainbowColors[i++ % rainbowColors.length]](letter); + } + }; +}; + diff --git a/node_modules/colors/lib/maps/random.js b/node_modules/colors/lib/maps/random.js new file mode 100644 index 0000000..3d82a39 --- /dev/null +++ b/node_modules/colors/lib/maps/random.js @@ -0,0 +1,11 @@ +module['exports'] = function(colors) { + var available = ['underline', 'inverse', 'grey', 'yellow', 'red', 'green', + 'blue', 'white', 'cyan', 'magenta', 'brightYellow', 'brightRed', + 'brightGreen', 'brightBlue', 'brightWhite', 'brightCyan', 'brightMagenta']; + return function(letter, i, exploded) { + return letter === ' ' ? letter : + colors[ + available[Math.round(Math.random() * (available.length - 2))] + ](letter); + }; +}; diff --git a/node_modules/colors/lib/maps/zebra.js b/node_modules/colors/lib/maps/zebra.js new file mode 100644 index 0000000..fa73623 --- /dev/null +++ b/node_modules/colors/lib/maps/zebra.js @@ -0,0 +1,5 @@ +module['exports'] = function(colors) { + return function(letter, i, exploded) { + return i % 2 === 0 ? letter : colors.inverse(letter); + }; +}; diff --git a/node_modules/colors/lib/styles.js b/node_modules/colors/lib/styles.js new file mode 100644 index 0000000..011dafd --- /dev/null +++ b/node_modules/colors/lib/styles.js @@ -0,0 +1,95 @@ +/* +The MIT License (MIT) + +Copyright (c) Sindre Sorhus (sindresorhus.com) + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +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: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +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. + +*/ + +var styles = {}; +module['exports'] = styles; + +var codes = { + reset: [0, 0], + + bold: [1, 22], + dim: [2, 22], + italic: [3, 23], + underline: [4, 24], + inverse: [7, 27], + hidden: [8, 28], + strikethrough: [9, 29], + + black: [30, 39], + red: [31, 39], + green: [32, 39], + yellow: [33, 39], + blue: [34, 39], + magenta: [35, 39], + cyan: [36, 39], + white: [37, 39], + gray: [90, 39], + grey: [90, 39], + + brightRed: [91, 39], + brightGreen: [92, 39], + brightYellow: [93, 39], + brightBlue: [94, 39], + brightMagenta: [95, 39], + brightCyan: [96, 39], + brightWhite: [97, 39], + + bgBlack: [40, 49], + bgRed: [41, 49], + bgGreen: [42, 49], + bgYellow: [43, 49], + bgBlue: [44, 49], + bgMagenta: [45, 49], + bgCyan: [46, 49], + bgWhite: [47, 49], + bgGray: [100, 49], + bgGrey: [100, 49], + + bgBrightRed: [101, 49], + bgBrightGreen: [102, 49], + bgBrightYellow: [103, 49], + bgBrightBlue: [104, 49], + bgBrightMagenta: [105, 49], + bgBrightCyan: [106, 49], + bgBrightWhite: [107, 49], + + // legacy styles for colors pre v1.0.0 + blackBG: [40, 49], + redBG: [41, 49], + greenBG: [42, 49], + yellowBG: [43, 49], + blueBG: [44, 49], + magentaBG: [45, 49], + cyanBG: [46, 49], + whiteBG: [47, 49], + +}; + +Object.keys(codes).forEach(function(key) { + var val = codes[key]; + var style = styles[key] = []; + style.open = '\u001b[' + val[0] + 'm'; + style.close = '\u001b[' + val[1] + 'm'; +}); diff --git a/node_modules/colors/lib/system/has-flag.js b/node_modules/colors/lib/system/has-flag.js new file mode 100644 index 0000000..a347dd4 --- /dev/null +++ b/node_modules/colors/lib/system/has-flag.js @@ -0,0 +1,35 @@ +/* +MIT License + +Copyright (c) Sindre Sorhus (sindresorhus.com) + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal 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: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +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. +*/ + +'use strict'; + +module.exports = function(flag, argv) { + argv = argv || process.argv; + + var terminatorPos = argv.indexOf('--'); + var prefix = /^-{1,2}/.test(flag) ? '' : '--'; + var pos = argv.indexOf(prefix + flag); + + return pos !== -1 && (terminatorPos === -1 ? true : pos < terminatorPos); +}; diff --git a/node_modules/colors/lib/system/supports-colors.js b/node_modules/colors/lib/system/supports-colors.js new file mode 100644 index 0000000..f1f9c8f --- /dev/null +++ b/node_modules/colors/lib/system/supports-colors.js @@ -0,0 +1,151 @@ +/* +The MIT License (MIT) + +Copyright (c) Sindre Sorhus (sindresorhus.com) + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +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: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +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. + +*/ + +'use strict'; + +var os = require('os'); +var hasFlag = require('./has-flag.js'); + +var env = process.env; + +var forceColor = void 0; +if (hasFlag('no-color') || hasFlag('no-colors') || hasFlag('color=false')) { + forceColor = false; +} else if (hasFlag('color') || hasFlag('colors') || hasFlag('color=true') + || hasFlag('color=always')) { + forceColor = true; +} +if ('FORCE_COLOR' in env) { + forceColor = env.FORCE_COLOR.length === 0 + || parseInt(env.FORCE_COLOR, 10) !== 0; +} + +function translateLevel(level) { + if (level === 0) { + return false; + } + + return { + level: level, + hasBasic: true, + has256: level >= 2, + has16m: level >= 3, + }; +} + +function supportsColor(stream) { + if (forceColor === false) { + return 0; + } + + if (hasFlag('color=16m') || hasFlag('color=full') + || hasFlag('color=truecolor')) { + return 3; + } + + if (hasFlag('color=256')) { + return 2; + } + + if (stream && !stream.isTTY && forceColor !== true) { + return 0; + } + + var min = forceColor ? 1 : 0; + + if (process.platform === 'win32') { + // Node.js 7.5.0 is the first version of Node.js to include a patch to + // libuv that enables 256 color output on Windows. Anything earlier and it + // won't work. However, here we target Node.js 8 at minimum as it is an LTS + // release, and Node.js 7 is not. Windows 10 build 10586 is the first + // Windows release that supports 256 colors. Windows 10 build 14931 is the + // first release that supports 16m/TrueColor. + var osRelease = os.release().split('.'); + if (Number(process.versions.node.split('.')[0]) >= 8 + && Number(osRelease[0]) >= 10 && Number(osRelease[2]) >= 10586) { + return Number(osRelease[2]) >= 14931 ? 3 : 2; + } + + return 1; + } + + if ('CI' in env) { + if (['TRAVIS', 'CIRCLECI', 'APPVEYOR', 'GITLAB_CI'].some(function(sign) { + return sign in env; + }) || env.CI_NAME === 'codeship') { + return 1; + } + + return min; + } + + if ('TEAMCITY_VERSION' in env) { + return (/^(9\.(0*[1-9]\d*)\.|\d{2,}\.)/.test(env.TEAMCITY_VERSION) ? 1 : 0 + ); + } + + if ('TERM_PROGRAM' in env) { + var version = parseInt((env.TERM_PROGRAM_VERSION || '').split('.')[0], 10); + + switch (env.TERM_PROGRAM) { + case 'iTerm.app': + return version >= 3 ? 3 : 2; + case 'Hyper': + return 3; + case 'Apple_Terminal': + return 2; + // No default + } + } + + if (/-256(color)?$/i.test(env.TERM)) { + return 2; + } + + if (/^screen|^xterm|^vt100|^rxvt|color|ansi|cygwin|linux/i.test(env.TERM)) { + return 1; + } + + if ('COLORTERM' in env) { + return 1; + } + + if (env.TERM === 'dumb') { + return min; + } + + return min; +} + +function getSupportLevel(stream) { + var level = supportsColor(stream); + return translateLevel(level); +} + +module.exports = { + supportsColor: getSupportLevel, + stdout: getSupportLevel(process.stdout), + stderr: getSupportLevel(process.stderr), +}; diff --git a/node_modules/colors/package.json b/node_modules/colors/package.json new file mode 100644 index 0000000..dbd71ba --- /dev/null +++ b/node_modules/colors/package.json @@ -0,0 +1,45 @@ +{ + "name": "colors", + "description": "get colors in your node.js console", + "version": "1.4.0", + "author": "Marak Squires", + "contributors": [ + { + "name": "DABH", + "url": "https://github.com/DABH" + } + ], + "homepage": "https://github.com/Marak/colors.js", + "bugs": "https://github.com/Marak/colors.js/issues", + "keywords": [ + "ansi", + "terminal", + "colors" + ], + "repository": { + "type": "git", + "url": "http://github.com/Marak/colors.js.git" + }, + "license": "MIT", + "scripts": { + "lint": "eslint . --fix", + "test": "node tests/basic-test.js && node tests/safe-test.js" + }, + "engines": { + "node": ">=0.1.90" + }, + "main": "lib/index.js", + "files": [ + "examples", + "lib", + "LICENSE", + "safe.js", + "themes", + "index.d.ts", + "safe.d.ts" + ], + "devDependencies": { + "eslint": "^5.2.0", + "eslint-config-google": "^0.11.0" + } +} diff --git a/node_modules/colors/safe.d.ts b/node_modules/colors/safe.d.ts new file mode 100644 index 0000000..2bafc27 --- /dev/null +++ b/node_modules/colors/safe.d.ts @@ -0,0 +1,48 @@ +// Type definitions for Colors.js 1.2 +// Project: https://github.com/Marak/colors.js +// Definitions by: Bart van der Schoor , Staffan Eketorp +// Definitions: https://github.com/Marak/colors.js + +export const enabled: boolean; +export function enable(): void; +export function disable(): void; +export function setTheme(theme: any): void; + +export function strip(str: string): string; +export function stripColors(str: string): string; + +export function black(str: string): string; +export function red(str: string): string; +export function green(str: string): string; +export function yellow(str: string): string; +export function blue(str: string): string; +export function magenta(str: string): string; +export function cyan(str: string): string; +export function white(str: string): string; +export function gray(str: string): string; +export function grey(str: string): string; + +export function bgBlack(str: string): string; +export function bgRed(str: string): string; +export function bgGreen(str: string): string; +export function bgYellow(str: string): string; +export function bgBlue(str: string): string; +export function bgMagenta(str: string): string; +export function bgCyan(str: string): string; +export function bgWhite(str: string): string; + +export function reset(str: string): string; +export function bold(str: string): string; +export function dim(str: string): string; +export function italic(str: string): string; +export function underline(str: string): string; +export function inverse(str: string): string; +export function hidden(str: string): string; +export function strikethrough(str: string): string; + +export function rainbow(str: string): string; +export function zebra(str: string): string; +export function america(str: string): string; +export function trap(str: string): string; +export function random(str: string): string; +export function zalgo(str: string): string; diff --git a/node_modules/colors/safe.js b/node_modules/colors/safe.js new file mode 100644 index 0000000..a013d54 --- /dev/null +++ b/node_modules/colors/safe.js @@ -0,0 +1,10 @@ +// +// Remark: Requiring this file will use the "safe" colors API, +// which will not touch String.prototype. +// +// var colors = require('colors/safe'); +// colors.red("foo") +// +// +var colors = require('./lib/colors'); +module['exports'] = colors; diff --git a/node_modules/colors/themes/generic-logging.js b/node_modules/colors/themes/generic-logging.js new file mode 100644 index 0000000..63adfe4 --- /dev/null +++ b/node_modules/colors/themes/generic-logging.js @@ -0,0 +1,12 @@ +module['exports'] = { + silly: 'rainbow', + input: 'grey', + verbose: 'cyan', + prompt: 'grey', + info: 'green', + data: 'grey', + help: 'cyan', + warn: 'yellow', + debug: 'blue', + error: 'red', +}; diff --git a/node_modules/dotenv/CHANGELOG.md b/node_modules/dotenv/CHANGELOG.md new file mode 100644 index 0000000..7bf933b --- /dev/null +++ b/node_modules/dotenv/CHANGELOG.md @@ -0,0 +1,155 @@ +# Changelog + +All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines. + +## [8.2.0](https://github.com/motdotla/dotenv/compare/v8.1.0...v8.2.0) (2019-10-16) + +## [8.1.0](https://github.com/motdotla/dotenv/compare/v7.0.0...v8.1.0) (2019-08-18) + + +### ⚠ BREAKING CHANGES + +* dropping Node v6 support because end-of-life + +* Drop support for Node v6 (#392) ([2e9636a](https://github.com/motdotla/dotenv/commit/2e9636a)), closes [#392](https://github.com/motdotla/dotenv/issues/392) + +# [8.0.0](https://github.com/motdotla/dotenv/compare/v7.0.0...v8.0.0) (2019-05-02) + +- Drop support for Node v6 (#392) ([2e9636a](https://github.com/motdotla/dotenv/commit/2e9636a)), closes [#392](https://github.com/motdotla/dotenv/issues/392) + +### BREAKING CHANGES + +- dropping Node v6 support because end-of-life + +## [7.0.0] - 2019-03-12 + +### Fixed + +- Fix removing unbalanced quotes ([#376](https://github.com/motdotla/dotenv/pull/376)) + +### Removed + +- Removed `load` alias for `config` for consistency throughout code and documentation. + +## [6.2.0] - 2018-12-03 + +### Added + +- Support preload configuration via environment variables ([#351](https://github.com/motdotla/dotenv/issues/351)) + +## [6.1.0] - 2018-10-08 + +### Added + +- `debug` option for `config` and `parse` methods will turn on logging + +## [6.0.0] - 2018-06-02 + +### Changed + +- _Breaking:_ drop support for Node v4 ([#304](https://github.com/motdotla/dotenv/pull/304)) + +## [5.0.0] - 2018-01-29 + +### Added + +- Testing against Node v8 and v9 +- Documentation on trim behavior of values +- Documentation on how to use with `import` + +### Changed + +- _Breaking_: default `path` is now `path.resolve(process.cwd(), '.env')` +- _Breaking_: does not write over keys already in `process.env` if the key has a falsy value +- using `const` and `let` instead of `var` + +### Removed + +- Testing against Node v7 + +## [4.0.0] - 2016-12-23 + +### Changed + +- Return Object with parsed content or error instead of false ([#165](https://github.com/motdotla/dotenv/pull/165)). + +### Removed + +- `verbose` option removed in favor of returning result. + +## [3.0.0] - 2016-12-20 + +### Added + +- `verbose` option will log any error messages. Off by default. +- parses email addresses correctly +- allow importing config method directly in ES6 + +### Changed + +- Suppress error messages by default ([#154](https://github.com/motdotla/dotenv/pull/154)) +- Ignoring more files for NPM to make package download smaller + +### Fixed + +- False positive test due to case-sensitive variable ([#124](https://github.com/motdotla/dotenv/pull/124)) + +### Removed + +- `silent` option removed in favor of `verbose` + +## [2.0.0] - 2016-01-20 + +### Added + +- CHANGELOG to ["make it easier for users and contributors to see precisely what notable changes have been made between each release"](http://keepachangelog.com/). Linked to from README +- LICENSE to be more explicit about what was defined in `package.json`. Linked to from README +- Testing nodejs v4 on travis-ci +- added examples of how to use dotenv in different ways +- return parsed object on success rather than boolean true + +### Changed + +- README has shorter description not referencing ruby gem since we don't have or want feature parity + +### Removed + +- Variable expansion and escaping so environment variables are encouraged to be fully orthogonal + +## [1.2.0] - 2015-06-20 + +### Added + +- Preload hook to require dotenv without including it in your code + +### Changed + +- clarified license to be "BSD-2-Clause" in `package.json` + +### Fixed + +- retain spaces in string vars + +## [1.1.0] - 2015-03-31 + +### Added + +- Silent option to silence `console.log` when `.env` missing + +## [1.0.0] - 2015-03-13 + +### Removed + +- support for multiple `.env` files. should always use one `.env` file for the current environment + +[7.0.0]: https://github.com/motdotla/dotenv/compare/v6.2.0...v7.0.0 +[6.2.0]: https://github.com/motdotla/dotenv/compare/v6.1.0...v6.2.0 +[6.1.0]: https://github.com/motdotla/dotenv/compare/v6.0.0...v6.1.0 +[6.0.0]: https://github.com/motdotla/dotenv/compare/v5.0.0...v6.0.0 +[5.0.0]: https://github.com/motdotla/dotenv/compare/v4.0.0...v5.0.0 +[4.0.0]: https://github.com/motdotla/dotenv/compare/v3.0.0...v4.0.0 +[3.0.0]: https://github.com/motdotla/dotenv/compare/v2.0.0...v3.0.0 +[2.0.0]: https://github.com/motdotla/dotenv/compare/v1.2.0...v2.0.0 +[1.2.0]: https://github.com/motdotla/dotenv/compare/v1.1.0...v1.2.0 +[1.1.0]: https://github.com/motdotla/dotenv/compare/v1.0.0...v1.1.0 +[1.0.0]: https://github.com/motdotla/dotenv/compare/v0.4.0...v1.0.0 diff --git a/node_modules/dotenv/LICENSE b/node_modules/dotenv/LICENSE new file mode 100644 index 0000000..c430ad8 --- /dev/null +++ b/node_modules/dotenv/LICENSE @@ -0,0 +1,23 @@ +Copyright (c) 2015, Scott Motte +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +* Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + +* Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/node_modules/dotenv/README.md b/node_modules/dotenv/README.md new file mode 100644 index 0000000..cf65c9e --- /dev/null +++ b/node_modules/dotenv/README.md @@ -0,0 +1,271 @@ +# dotenv + +dotenv + +Dotenv is a zero-dependency module that loads environment variables from a `.env` file into [`process.env`](https://nodejs.org/docs/latest/api/process.html#process_process_env). Storing configuration in the environment separate from code is based on [The Twelve-Factor App](http://12factor.net/config) methodology. + +[![BuildStatus](https://img.shields.io/travis/motdotla/dotenv/master.svg?style=flat-square)](https://travis-ci.org/motdotla/dotenv) +[![Build status](https://ci.appveyor.com/api/projects/status/github/motdotla/dotenv?svg=true)](https://ci.appveyor.com/project/motdotla/dotenv/branch/master) +[![NPM version](https://img.shields.io/npm/v/dotenv.svg?style=flat-square)](https://www.npmjs.com/package/dotenv) +[![js-standard-style](https://img.shields.io/badge/code%20style-standard-brightgreen.svg?style=flat-square)](https://github.com/feross/standard) +[![Coverage Status](https://img.shields.io/coveralls/motdotla/dotenv/master.svg?style=flat-square)](https://coveralls.io/github/motdotla/dotenv?branch=coverall-intergration) +[![LICENSE](https://img.shields.io/github/license/motdotla/dotenv.svg)](LICENSE) +[![Conventional Commits](https://img.shields.io/badge/Conventional%20Commits-1.0.0-yellow.svg)](https://conventionalcommits.org) + +## Install + +```bash +# with npm +npm install dotenv + +# or with Yarn +yarn add dotenv +``` + +## Usage + +As early as possible in your application, require and configure dotenv. + +```javascript +require('dotenv').config() +``` + +Create a `.env` file in the root directory of your project. Add +environment-specific variables on new lines in the form of `NAME=VALUE`. +For example: + +```dosini +DB_HOST=localhost +DB_USER=root +DB_PASS=s1mpl3 +``` + +`process.env` now has the keys and values you defined in your `.env` file. + +```javascript +const db = require('db') +db.connect({ + host: process.env.DB_HOST, + username: process.env.DB_USER, + password: process.env.DB_PASS +}) +``` + +### Preload + +You can use the `--require` (`-r`) [command line option](https://nodejs.org/api/cli.html#cli_r_require_module) to preload dotenv. By doing this, you do not need to require and load dotenv in your application code. This is the preferred approach when using `import` instead of `require`. + +```bash +$ node -r dotenv/config your_script.js +``` + +The configuration options below are supported as command line arguments in the format `dotenv_config_