forked from Hri7566/mpp-server-dev2
properly add quotas
This commit is contained in:
parent
78d24224d6
commit
df6e80e306
19
Quotas.js
19
Quotas.js
|
@ -1,21 +1,4 @@
|
||||||
module.exports = Object.seal({
|
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: {
|
chat: {
|
||||||
lobby: {
|
lobby: {
|
||||||
amount: 4,
|
amount: 4,
|
||||||
|
@ -34,7 +17,7 @@ module.exports = Object.seal({
|
||||||
amount: 10,
|
amount: 10,
|
||||||
time: 5000
|
time: 5000
|
||||||
},
|
},
|
||||||
name: {
|
userset: {
|
||||||
amount: 30,
|
amount: 30,
|
||||||
time: 30 * 60000
|
time: 30 * 60000
|
||||||
},
|
},
|
||||||
|
|
3
TODO.md
3
TODO.md
|
@ -1,3 +0,0 @@
|
||||||
1. Send noteQuota on room owner change.
|
|
||||||
2. Add noteQuota server side.
|
|
||||||
3. Room.js make color verifier
|
|
2
index.js
2
index.js
|
@ -15,7 +15,7 @@ global.isObj = function(a){
|
||||||
return typeof a === "object" && !Array.isArray(a) && a !== null;
|
return typeof a === "object" && !Array.isArray(a) && a !== null;
|
||||||
}
|
}
|
||||||
|
|
||||||
let Server = require("./src/Server");
|
let Server = require("./src/Server.js");
|
||||||
let config = require('./config');
|
let config = require('./config');
|
||||||
global.SERVER = new Server(config);
|
global.SERVER = new Server(config);
|
||||||
let console = process.platform == 'win32' ? new AsyncConsole("", input => {
|
let console = process.platform == 'win32' ? new AsyncConsole("", input => {
|
||||||
|
|
|
@ -1,4 +1,8 @@
|
||||||
const Room = require("./Room.js");
|
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');
|
require('node-json-color-stringify');
|
||||||
class Client extends EventEmitter {
|
class Client extends EventEmitter {
|
||||||
constructor(ws, req, server) {
|
constructor(ws, req, server) {
|
||||||
|
@ -9,6 +13,10 @@ class Client extends EventEmitter {
|
||||||
this.server = server;
|
this.server = server;
|
||||||
this.participantId;
|
this.participantId;
|
||||||
this.channel;
|
this.channel;
|
||||||
|
this.staticQuotas = {
|
||||||
|
room: new RateLimit(quotas.room.time)
|
||||||
|
};
|
||||||
|
this.quotas = {};
|
||||||
this.ws = ws;
|
this.ws = ws;
|
||||||
this.req = req;
|
this.req = req;
|
||||||
this.ip = (req.connection.remoteAddress).replace("::ffff:", "");
|
this.ip = (req.connection.remoteAddress).replace("::ffff:", "");
|
||||||
|
@ -62,6 +70,25 @@ class Client extends EventEmitter {
|
||||||
this.ws.send(JSON.stringify(arr));
|
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() {
|
destroy() {
|
||||||
this.ws.close();
|
this.ws.close();
|
||||||
if (this.channel) {
|
if (this.channel) {
|
||||||
|
|
130
src/Message.js
130
src/Message.js
|
@ -1,6 +1,6 @@
|
||||||
const NoteQuotas = require('../Quotas');
|
const Quota = require('./Quota');
|
||||||
let quotas;
|
|
||||||
const User = require("./User.js");
|
const User = require("./User.js");
|
||||||
|
const Room = require("./Room.js");
|
||||||
module.exports = (cl) => {
|
module.exports = (cl) => {
|
||||||
cl.once("hi", () => {
|
cl.once("hi", () => {
|
||||||
let user = new User(cl);
|
let user = new User(cl);
|
||||||
|
@ -13,7 +13,6 @@ module.exports = (cl) => {
|
||||||
msg.v = "Beta";
|
msg.v = "Beta";
|
||||||
cl.sendArray([msg])
|
cl.sendArray([msg])
|
||||||
cl.user = data;
|
cl.user = data;
|
||||||
quotas = cl.server.connections[cl.user._id].quotas;
|
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
cl.on("t", msg => {
|
cl.on("t", msg => {
|
||||||
|
@ -25,24 +24,31 @@ module.exports = (cl) => {
|
||||||
}])
|
}])
|
||||||
})
|
})
|
||||||
cl.on("ch", msg => {
|
cl.on("ch", msg => {
|
||||||
if (!quotas.room.attempt()) return;
|
|
||||||
if (!msg.hasOwnProperty("set") || !msg.set) msg.set = {};
|
if (!msg.hasOwnProperty("set") || !msg.set) msg.set = {};
|
||||||
if (msg.hasOwnProperty("_id") && typeof msg._id == "string") {
|
if (msg.hasOwnProperty("_id") && typeof msg._id == "string") {
|
||||||
if (msg._id.length > 512) return;
|
if (msg._id.length > 512) return;
|
||||||
|
if (!cl.staticQuotas.room.attempt()) return;
|
||||||
cl.setChannel(msg._id, msg.set);
|
cl.setChannel(msg._id, msg.set);
|
||||||
|
let param;
|
||||||
if (cl.channel.isLobby(cl.channel._id)) {
|
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 {
|
} else {
|
||||||
if (!(cl.user._id == cl.channel.crown.userId)) {
|
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 {
|
} 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 => {
|
cl.on("m", (msg, admin) => {
|
||||||
if (!quotas.cursor.attempt()) return;
|
if (!cl.quotas.cursor.attempt() && !admin) return;
|
||||||
if (!(cl.channel && cl.participantId)) return;
|
if (!(cl.channel && cl.participantId)) return;
|
||||||
if (!msg.hasOwnProperty("x")) msg.x = null;
|
if (!msg.hasOwnProperty("x")) msg.x = null;
|
||||||
if (!msg.hasOwnProperty("y")) msg.y = 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.channel.emit("m", cl, msg.x, msg.y)
|
||||||
|
|
||||||
})
|
})
|
||||||
cl.on("chown", msg => {
|
cl.on("chown", (msg, admin) => {
|
||||||
if (!quotas.chown.attempt()) return;
|
if (!cl.quotas.chown.attempt() && !admin) return;
|
||||||
if (!(cl.channel && cl.participantId)) return;
|
if (!(cl.channel && cl.participantId)) return;
|
||||||
//console.log((Date.now() - cl.channel.crown.time))
|
//console.log((Date.now() - cl.channel.crown.time))
|
||||||
//console.log(!(cl.channel.crown.userId != cl.user._id), !((Date.now() - cl.channel.crown.time) > 15000));
|
//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)
|
// console.log(cl.channel.crown)
|
||||||
if (cl.user._id == cl.channel.crown.userId || cl.channel.crowndropped)
|
if (cl.user._id == cl.channel.crown.userId || cl.channel.crowndropped)
|
||||||
cl.channel.chown(msg.id);
|
cl.channel.chown(msg.id);
|
||||||
|
if (msg.id == cl.user.id) {
|
||||||
|
param = Quota.N_PARAMS_RIDICULOUS;
|
||||||
|
param.m = "nq";
|
||||||
|
cl.sendArray([param])
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
if (cl.user._id == cl.channel.crown.userId || cl.channel.crowndropped)
|
if (cl.user._id == cl.channel.crown.userId || cl.channel.crowndropped)
|
||||||
cl.channel.chown();
|
cl.channel.chown();
|
||||||
|
param = Quota.N_PARAMS_NORMAL;
|
||||||
|
param.m = "nq";
|
||||||
|
cl.sendArray([param])
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
cl.on("chset", msg => {
|
cl.on("chset", msg => {
|
||||||
|
@ -73,19 +87,19 @@ module.exports = (cl) => {
|
||||||
cl.channel.settings = msg.set;
|
cl.channel.settings = msg.set;
|
||||||
cl.channel.updateCh();
|
cl.channel.updateCh();
|
||||||
})
|
})
|
||||||
cl.on("a", msg => {
|
cl.on("a", (msg, admin) => {
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (!(cl.channel && cl.participantId)) return;
|
if (!(cl.channel && cl.participantId)) return;
|
||||||
if (!msg.hasOwnProperty('message')) return;
|
if (!msg.hasOwnProperty('message')) return;
|
||||||
if (cl.channel.settings.chat) {
|
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);
|
cl.channel.emit('a', cl, msg);
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
@ -123,11 +137,11 @@ module.exports = (cl) => {
|
||||||
cl.server.roomlisteners.delete(cl.connectionid);
|
cl.server.roomlisteners.delete(cl.connectionid);
|
||||||
})
|
})
|
||||||
cl.on("userset", msg => {
|
cl.on("userset", msg => {
|
||||||
if (!quotas.name.attempt()) return;
|
|
||||||
if (!(cl.channel && cl.participantId)) return;
|
if (!(cl.channel && cl.participantId)) return;
|
||||||
if (!msg.hasOwnProperty("set") || !msg.set) msg.set = {};
|
if (!msg.hasOwnProperty("set") || !msg.set) msg.set = {};
|
||||||
if (msg.set.hasOwnProperty('name') && typeof msg.set.name == "string") {
|
if (msg.set.hasOwnProperty('name') && typeof msg.set.name == "string") {
|
||||||
if (msg.set.name.length > 40) return;
|
if (msg.set.name.length > 40) return;
|
||||||
|
if (!cl.quotas.name.attempt()) return;
|
||||||
cl.user.name = msg.set.name;
|
cl.user.name = msg.set.name;
|
||||||
let user = new User(cl);
|
let user = new User(cl);
|
||||||
user.getUserData().then((usr) => {
|
user.getUserData().then((usr) => {
|
||||||
|
@ -145,10 +159,10 @@ module.exports = (cl) => {
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
cl.on('kickban', msg => {
|
cl.on('kickban', msg => {
|
||||||
if (!quotas.kickban.attempt()) return;
|
|
||||||
if (!(cl.channel && cl.participantId)) return;
|
if (!(cl.channel && cl.participantId)) return;
|
||||||
if (!(cl.user._id == cl.channel.crown.userId)) return;
|
if (!(cl.user._id == cl.channel.crown.userId)) return;
|
||||||
if (msg.hasOwnProperty('_id') && typeof msg._id == "string") {
|
if (msg.hasOwnProperty('_id') && typeof msg._id == "string") {
|
||||||
|
if (!cl.quotas.kickban.attempt() && !admin) return;
|
||||||
let _id = msg._id;
|
let _id = msg._id;
|
||||||
let ms = msg.ms || 0;
|
let ms = msg.ms || 0;
|
||||||
cl.channel.kickban(_id, ms);
|
cl.channel.kickban(_id, ms);
|
||||||
|
@ -157,7 +171,7 @@ module.exports = (cl) => {
|
||||||
cl.on("bye", msg => {
|
cl.on("bye", msg => {
|
||||||
cl.destroy();
|
cl.destroy();
|
||||||
})
|
})
|
||||||
cl.on("admin message" || "adminmsg" || "admin msg", msg => {
|
cl.on("admin message", msg => {
|
||||||
if (!(cl.channel && cl.participantId)) return;
|
if (!(cl.channel && cl.participantId)) return;
|
||||||
if (!msg.hasOwnProperty('password') || !msg.hasOwnProperty('msg')) return;
|
if (!msg.hasOwnProperty('password') || !msg.hasOwnProperty('msg')) return;
|
||||||
if (typeof msg.msg != 'object') return;
|
if (typeof msg.msg != 'object') return;
|
||||||
|
@ -165,17 +179,7 @@ module.exports = (cl) => {
|
||||||
cl.ws.emit("message", JSON.stringify([msg.msg]), true);
|
cl.ws.emit("message", JSON.stringify([msg.msg]), true);
|
||||||
})
|
})
|
||||||
//admin only stuff
|
//admin only stuff
|
||||||
/*
|
cl.on('color', (msg, admin) => {
|
||||||
|
|
||||||
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 (!admin) return;
|
||||||
if (typeof cl.channel.verifyColor(msg.color) != 'string') return;
|
if (typeof cl.channel.verifyColor(msg.color) != 'string') return;
|
||||||
if (!msg.hasOwnProperty('id') && !msg.hasOwnProperty('_id')) return;
|
if (!msg.hasOwnProperty('id') && !msg.hasOwnProperty('_id')) return;
|
||||||
|
@ -188,12 +192,10 @@ module.exports = (cl) => {
|
||||||
let dbentry = user.userdb.get(uSr._id);
|
let dbentry = user.userdb.get(uSr._id);
|
||||||
if (!dbentry) return;
|
if (!dbentry) return;
|
||||||
dbentry.color = msg.color;
|
dbentry.color = msg.color;
|
||||||
dbentry.noteColor = msg.color;
|
//user.updatedb();
|
||||||
user.updatedb();
|
|
||||||
cl.server.rooms.forEach((room) => {
|
cl.server.rooms.forEach((room) => {
|
||||||
room.updateParticipant(usr.participantId, {
|
room.updateParticipant(usr.participantId, {
|
||||||
color: msg.color,
|
color: msg.color
|
||||||
noteColor: 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);
|
|
||||||
})
|
|
||||||
}
|
}
|
214
src/Quota.js
214
src/Quota.js
|
@ -1,58 +1,158 @@
|
||||||
function RateLimit(a,b){
|
//Adaptation of https://gist.github.com/brandon-lockaby/7339587 into modern javascript.
|
||||||
this.a = b.a || 1;
|
/*
|
||||||
this.m = b.m || 10;
|
class RateLimit {
|
||||||
this.mh = b.mh || 3;
|
constructor(interval_ms) {
|
||||||
this.setParams(a,{a:this.a,m:this.m,mh:this.mh});
|
this._interval_ms = interval_ms || 0; // (0 means no limit)
|
||||||
this.resetPoints();
|
this._after = 0;
|
||||||
if(a !== null){
|
}
|
||||||
var self = this;
|
attempt(time) {
|
||||||
this.giveInt = setInterval(()=>{self.give()},a);
|
var time = time || Date.now();
|
||||||
};
|
if(time < this._after) return false;
|
||||||
};
|
this._after = time + this._interval_ms;
|
||||||
RateLimit.prototype.setParams = function(a,b){
|
return true;
|
||||||
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.mh; i++) this.history.unshift(this.points);
|
|
||||||
};
|
|
||||||
RateLimit.prototype.give = function(){
|
|
||||||
this.history.unshift(this.points);
|
|
||||||
this.history.length = this.mh;
|
|
||||||
if(this.points < this.m){
|
|
||||||
this.points += this.a;
|
|
||||||
if(this.points > 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;
|
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
|
34
src/Room.js
34
src/Room.js
|
@ -2,7 +2,7 @@
|
||||||
//room class
|
//room class
|
||||||
//room deleter
|
//room deleter
|
||||||
//databases in Map
|
//databases in Map
|
||||||
|
const Quota = require("./Quota.js");
|
||||||
class Room extends EventEmitter {
|
class Room extends EventEmitter {
|
||||||
constructor(server, _id, settings) {
|
constructor(server, _id, settings) {
|
||||||
super();
|
super();
|
||||||
|
@ -11,7 +11,9 @@ class Room extends EventEmitter {
|
||||||
this.server = server;
|
this.server = server;
|
||||||
this.crown = null;
|
this.crown = null;
|
||||||
this.crowndropped = false;
|
this.crowndropped = false;
|
||||||
this.settings = this.verifySet(this._id,{set:settings});
|
this.settings = this.verifySet(this._id, {
|
||||||
|
set: settings
|
||||||
|
});
|
||||||
this.chatmsgs = [];
|
this.chatmsgs = [];
|
||||||
this.ppl = new Map();
|
this.ppl = new Map();
|
||||||
this.connections = [];
|
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);
|
let participantId = createKeccakHash('keccak256').update((Math.random().toString() + cl.ip)).digest('hex').substr(0, 24);
|
||||||
cl.user.id = participantId;
|
cl.user.id = participantId;
|
||||||
cl.participantId = 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.
|
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 = {
|
this.crown = {
|
||||||
participantId: cl.participantId,
|
participantId: cl.participantId,
|
||||||
userId: cl.user._id,
|
userId: cl.user._id,
|
||||||
|
@ -40,8 +44,11 @@ class Room extends EventEmitter {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
this.crowndropped = false;
|
this.crowndropped = false;
|
||||||
|
} else {
|
||||||
|
//cl.quotas.a.setParams(Quota.PARAMS_A_NORMAL);
|
||||||
}
|
}
|
||||||
this.ppl.set(participantId, cl);
|
this.ppl.set(participantId, cl);
|
||||||
|
|
||||||
this.connections.push(cl);
|
this.connections.push(cl);
|
||||||
this.sendArray([{
|
this.sendArray([{
|
||||||
color: this.ppl.get(cl.participantId).user.color,
|
color: this.ppl.get(cl.participantId).user.color,
|
||||||
|
@ -60,6 +67,7 @@ class Room extends EventEmitter {
|
||||||
} else {
|
} else {
|
||||||
cl.user.id = otheruser.participantId;
|
cl.user.id = otheruser.participantId;
|
||||||
cl.participantId = otheruser.participantId;
|
cl.participantId = otheruser.participantId;
|
||||||
|
cl.quotas = otheruser.quotas;
|
||||||
this.connections.push(cl);
|
this.connections.push(cl);
|
||||||
cl.sendArray([{
|
cl.sendArray([{
|
||||||
m: "c",
|
m: "c",
|
||||||
|
@ -173,12 +181,12 @@ class Room extends EventEmitter {
|
||||||
}
|
}
|
||||||
return data;
|
return data;
|
||||||
}
|
}
|
||||||
verifyColor(strColor){
|
verifyColor(strColor) {
|
||||||
var test2 = /^#[0-9A-F]{6}$/i.test(strColor);
|
var test2 = /^#[0-9A-F]{6}$/i.test(strColor);
|
||||||
if(test2 == true){
|
if (test2 == true) {
|
||||||
return strColor;
|
return strColor;
|
||||||
} else{
|
} else {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
isLobby(_id) {
|
isLobby(_id) {
|
||||||
|
@ -188,14 +196,14 @@ class Room extends EventEmitter {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
if (!(parseInt(lobbynum).toString() == lobbynum)) return false;
|
if (!(parseInt(lobbynum).toString() == lobbynum)) return false;
|
||||||
for (let i in lobbynum) {
|
for (let i in lobbynum) {
|
||||||
if (parseInt(lobbynum[i]) >= 0) {
|
if (parseInt(lobbynum[i]) >= 0) {
|
||||||
if (parseInt(i) + 1 == lobbynum.length) return true;
|
if (parseInt(i) + 1 == lobbynum.length) return true;
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
return false;
|
return false;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
} else if (_id.startsWith("test/")) {
|
} else if (_id.startsWith("test/")) {
|
||||||
if (_id == "test/") {
|
if (_id == "test/") {
|
||||||
return false;
|
return false;
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
const Client = require("./Client.js");
|
const Client = require("./Client.js");
|
||||||
const banned = require('../banned.json');
|
const banned = require('../banned.json');
|
||||||
|
|
||||||
class Server extends EventEmitter {
|
class Server extends EventEmitter {
|
||||||
constructor(config) {
|
constructor(config) {
|
||||||
super();
|
super();
|
||||||
|
@ -20,30 +19,7 @@ class Server extends EventEmitter {
|
||||||
this.wss.on('connection', (ws, req) => {
|
this.wss.on('connection', (ws, req) => {
|
||||||
this.connections.set(++this.connectionid, new Client(ws, req, this));
|
this.connections.set(++this.connectionid, new Client(ws, req, this));
|
||||||
});
|
});
|
||||||
this.legit_m = [
|
this.legit_m = ["a", "bye", "hi", "ch", "+ls", "-ls", "m", "n", "devices", "t", "chset", "userset", "chown", "kickban", "admin message", "color"]
|
||||||
"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.welcome_motd = config.motd || "You agree to read this message.";
|
||||||
this._id_Private_Key = config._id_PrivateKey || "boppity";
|
this._id_Private_Key = config._id_PrivateKey || "boppity";
|
||||||
this.defaultUsername = config.defaultUsername || "Anonymous";
|
this.defaultUsername = config.defaultUsername || "Anonymous";
|
||||||
|
|
|
@ -0,0 +1,2 @@
|
||||||
|
|
||||||
|
Room.js make color verifier
|
23
src/User.js
23
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 ColorEncoder = require("./ColorEncoder.js");
|
||||||
const { promisify } = require('util');
|
const { promisify } = require('util');
|
||||||
let userdb;
|
let userdb;
|
||||||
|
@ -16,26 +13,6 @@ class User {
|
||||||
await this.setUpDb();
|
await this.setUpDb();
|
||||||
}
|
}
|
||||||
let _id = createKeccakHash('keccak256').update((this.cl.server._id_Private_Key + this.cl.ip)).digest('hex').substr(0, 24);
|
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);
|
let usertofind = userdb.get(_id);
|
||||||
if (!usertofind) {
|
if (!usertofind) {
|
||||||
if (typeof usertofind == 'object' && (usertofind.hasOwnProperty('name') && usertofind.name != this.server.defaultUsername)) return;
|
if (typeof usertofind == 'object' && (usertofind.hasOwnProperty('name') && usertofind.name != this.server.defaultUsername)) return;
|
||||||
|
|
|
@ -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"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
Loading…
Reference in New Issue