best update ever

This commit is contained in:
Hri7566 2021-05-09 04:52:41 -04:00
parent 35c52b5a12
commit 2f33925be5
17 changed files with 1426 additions and 2110 deletions

1
.gitignore vendored
View File

@ -2,3 +2,4 @@
node_modules node_modules
ssl/ ssl/
src/db/users.json src/db/users.json
.history

View File

@ -31,4 +31,4 @@ module.exports = Object.seal({
amount: 2, amount: 2,
time: 1000 time: 1000
} }
}) });

View File

@ -4,15 +4,15 @@ module.exports = Object.seal({
_id_PrivateKey: process.env.SALT, _id_PrivateKey: process.env.SALT,
defaultUsername: "Anonymous", defaultUsername: "Anonymous",
// defaultRoomColor: "#3b5054", // defaultRoomColor: "#3b5054",
defaultRoomColor: "#000000",
// defaultLobbyColor: "#19b4b9", // defaultLobbyColor: "#19b4b9",
defaultLobbyColor: "#9900ff", defaultLobbyColor: "#76b0db",
// defaultLobbyColor2: "#801014", // defaultLobbyColor2: "#801014",
defaultLobbyColor2: "#801014", defaultLobbyColor2: "#276491",
adminpass: process.env.ADMINPASS, adminpass: process.env.ADMINPASS,
ssl: true, ssl: false,
defaultRoomSettings: { defaultRoomSettings: {
color: "#000000", color: "#3b5054",
color2: "#001014",
crownsolo: false, crownsolo: false,
visible: true visible: true
} }

1026
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -26,6 +26,8 @@
"dotenv": "^8.2.0", "dotenv": "^8.2.0",
"events": "^3.1.0", "events": "^3.1.0",
"keccak": "^2.1.0", "keccak": "^2.1.0",
"level": "^7.0.0",
"mongoose": "^5.12.7",
"node-json-color-stringify": "^1.1.0", "node-json-color-stringify": "^1.1.0",
"ws": "^7.2.3" "ws": "^7.2.3"
} }

View File

@ -71,7 +71,9 @@ class Client extends EventEmitter {
if (channel) this.channel.updateCh(this); if (channel) this.channel.updateCh(this);
this.channel = this.server.rooms.get(_id); this.channel = this.server.rooms.get(_id);
if (!this.user.hasFlag("hidden", true)) {
this.channel.join(this); this.channel.join(this);
}
} else { } else {
let room = new Room(this.server, _id, settings); let room = new Room(this.server, _id, settings);
this.server.rooms.set(_id, room); this.server.rooms.set(_id, room);
@ -109,7 +111,7 @@ class Client extends EventEmitter {
destroy() { destroy() {
this.ws.close(); this.ws.close();
if (this.channel) { if (this.channel) {
this.channel.emit("bye", this) this.channel.emit("bye", this);
} }
this.user; this.user;
this.participantId; this.participantId;
@ -118,7 +120,7 @@ class Client extends EventEmitter {
this.connectionid; this.connectionid;
this.server.connections.delete(this.connectionid); this.server.connections.delete(this.connectionid);
this.destroied = true; this.destroied = true;
console.log(`Removed Connection ${this.connectionid}.`); console.log(`Removed Connection ${this.connectionid}. user is ${this.user}`);
} }
bindEventListeners() { bindEventListeners() {

19
src/Crown.js Normal file
View File

@ -0,0 +1,19 @@
module.exports = class Crown {
constructor (id, _id) {
this.participantId = id;
this.userId = _id;
this.time = Date.now();
this.startPos = {
x: 50,
y: 50
}
this.endPos = {
x: Crown.generateRandomPos(),
y: Crown.generateRandomPos()
}
}
static generateRandomPos() {
return Math.floor(Math.random() * 10000) / 100;
}
}

View File

@ -2,57 +2,143 @@ const fs = require('fs');
const { promisify } = require('util'); const { promisify } = require('util');
const createKeccakHash = require('keccak'); const createKeccakHash = require('keccak');
const ColorEncoder = require('./ColorEncoder'); const ColorEncoder = require('./ColorEncoder');
const UserModel = require('./UserModel');
const mongoose = require('mongoose');
const level = require('level');
const { db } = require('./UserModel');
mongoose.connect(process.env.MONGO_URL, {
useNewUrlParser: true,
useUnifiedTopology: true
}, err => {
if (err) {
console.error(err);
return;
}
console.log("Connected to Database");
});
class Database { class Database {
static userdb; static userdb;
static roomdb;
static async load() { static async load() {
const writeFile = promisify(fs.writeFile); this.userdb = mongoose.connection;
const readdir = promisify(fs.readdir); this.roomdb = level('src/db/rooms.db');
// const writeFile = promisify(fs.writeFile);
// const readdir = promisify(fs.readdir);
let files = await readdir("src/db/"); // let files = await readdir("src/db/");
if (!files.includes("users.json")) { // if (!files.includes("users.json")) {
await writeFile('src/db/users.json', JSON.stringify(this.default_db, null, 2)) // await writeFile('src/db/users.json', JSON.stringify(this.default_db, null, 2))
this.userdb = new Map(Object.entries(require("./db/users.json"))); // this.userdb = new Map(Object.entries(require("./db/users.json")));
} else { // } else {
this.userdb = new Map(Object.entries(require("./db/users.json"))); // this.userdb = new Map(Object.entries(require("./db/users.json")));
} // }
} }
static async getUserData(cl, server) { static async getUserData(cl, server) {
if (!this.userdb || (this.userdb instanceof Map && [...this.userdb.entries()] == [])) { if (!this.userdb) {
await this.load(); await this.load();
} }
let _id = createKeccakHash('keccak256').update((cl.server._id_Private_Key + cl.ip)).digest('hex').substr(0, 24); let _id = createKeccakHash('keccak256').update((cl.server._id_Private_Key + cl.ip)).digest('hex').substr(0, 24);
let usertofind = this.userdb.get(_id); let user = await UserModel.findOne({ _id: _id }).exec();
if (!usertofind) { if (user == null) {
if (typeof usertofind == 'object' && (usertofind.hasOwnProperty('name') && usertofind.name != this.server.defaultUsername)) return; user = this.createUser(_id);
this.userdb.set(_id, {
"color": `#${ColorEncoder.intToRGB(ColorEncoder.hashCode(_id)).toLowerCase()}`,
"name": server.defaultUsername,
"_id": _id,
"ip": cl.ip
});
this.update();
} }
let user = this.userdb.get(_id); console.log('user flags:');
console.log(user.flags);
return user; return user;
} }
static async update() { static async createUser(_id) {
const writeFile = promisify(fs.writeFile); let user = new UserModel({
await writeFile('src/db/users.json', JSON.stringify(this.strMapToObj(this.userdb), null, 2)); name: "Anonymous",
_id: _id,
color: "#" + ColorEncoder.intToRGB(ColorEncoder.hashCode(_id)),
flags: {
}
});
user.save();
return user;
}
static async updateUser(_id, data) {
UserModel.findById(_id, (err, doc) => {
if (err) {
console.error(err);
return err;
}
if (!doc) {
return console.warn('Could not find user to save.');
}
doc.set(data);
doc.save();
});
}
static async wipe() {
await UserModel.find({}, (err, docs) => {
docs.forEach(doc => {
doc.remove();
});
}).exec();
} }
static strMapToObj(strMap) { static strMapToObj(strMap) {
return [...strMap.entries()].reduce((obj, [key, value]) => (obj[key] = value, obj), {}); return [...strMap.entries()].reduce((obj, [key, value]) => (obj[key] = value, obj), {});
} }
static getRoomSettings(_id, cb) {
let key = "room~"+_id;
roomSettings
this.roomdb.get(key, (err, value) => {
if (err || !value || value == "") {
cb(err, value);
return;
}
cb(undefined, value);
});
}
static setRoomSettings(_id, roomSettings, chat) {
let roomData = new RoomDataModel(roomSettings, chat);
let key = "room~"+_id;
this.roomdb.put(key, JSON.stringify(roomData));
}
static getRoomSettings(_id, cb) {
let key = "room~"+_id;
this.roomdb.get(key, (err, value) => {
if (err) {
cb(err);
return;
}
let settings = JSON.parse(value);
cb(err, settings);
});
}
static deleteRoomSettings(_id) {
this.roomdb.del("room~"+_id);
}
}
class RoomDataModel {
constructor (settings, chat) {
this.settings = settings;
this.chat = chat;
}
} }
module.exports = Database; module.exports = Database;

View File

@ -6,6 +6,7 @@ const Database = require('./Database');
module.exports = (cl) => { module.exports = (cl) => {
cl.once("hi", (msg, admin) => { cl.once("hi", (msg, admin) => {
console.log('hi on')
if (msg.hasOwnProperty("password")) { if (msg.hasOwnProperty("password")) {
if (msg.password == "hideme") { if (msg.password == "hideme") {
cl.hidden = true; cl.hidden = true;
@ -23,8 +24,7 @@ module.exports = (cl) => {
color: cl.user.color color: cl.user.color
}; };
m.v = "https://gitlab.com/hri7566/mpp-server"; m.v = "2.0";
cl.sendArray([m]); cl.sendArray([m]);
}); });
@ -40,7 +40,7 @@ module.exports = (cl) => {
cl.on("ch", msg => { cl.on("ch", msg => {
if (typeof(msg.set) !== 'object') msg.set = {}; if (typeof(msg.set) !== 'object') msg.set = {};
if (msg.hasOwnProperty("_id") && typeof msg._id == "string") { if (typeof(msg._id) == "string") {
if (msg._id.length > 512) return; if (msg._id.length > 512) return;
if (!cl.staticQuotas.room.attempt()) return; if (!cl.staticQuotas.room.attempt()) return;
@ -57,8 +57,12 @@ module.exports = (cl) => {
} }
} }
param.m = "nq"; param.m = "nq";
setTimeout(() => {
cl.user.checkFlags();
cl.sendArray([param]); cl.sendArray([param]);
}, 1000);
} }
}); });
@ -164,7 +168,7 @@ module.exports = (cl) => {
cl.server.roomlisteners.set(cl.connectionid, cl); cl.server.roomlisteners.set(cl.connectionid, cl);
let rooms = []; let rooms = [];
for (let room of Array.from(cl.server.rooms.values())) { for (let room of Array.from(cl.server.rooms.values())) {
let data = room.fetchData().ch; let data = room.fetchChannelData().ch;
if (room.bans.get(cl.user._id)) { if (room.bans.get(cl.user._id)) {
data.banned = true; data.banned = true;
} }
@ -190,10 +194,11 @@ module.exports = (cl) => {
if(!cl.quotas.userset.attempt()) return; if(!cl.quotas.userset.attempt()) return;
cl.user.name = msg.set.name; cl.user.name = msg.set.name;
Database.getUserData(cl, cl.server).then((usr) => { Database.getUserData(cl, cl.server).then((usr) => {
let dbentry = Database.userdb.get(cl.user._id); // let dbentry = Database.userdb.get(cl.user._id);
if (!dbentry) return; // if (!dbentry) return;
dbentry.name = msg.set.name; // dbentry.name = msg.set.name;
Database.update(); // Database.update();
Database.updateUser(cl.user._id, cl.user);
cl.server.rooms.forEach((room) => { cl.server.rooms.forEach((room) => {
room.updateParticipant(cl.user._id, { room.updateParticipant(cl.user._id, {
name: msg.set.name name: msg.set.name
@ -218,6 +223,7 @@ module.exports = (cl) => {
}); });
cl.on("bye", msg => { cl.on("bye", msg => {
clearInterval(cl.user.rainbow);
cl.destroy(); cl.destroy();
}); });
@ -264,7 +270,52 @@ module.exports = (cl) => {
cl.on('notification', (msg, admin) => { cl.on('notification', (msg, admin) => {
if (!admin) return; if (!admin) return;
if (!msg.hasOwnProperty("id") || (!msg.hasOwnProperty("targetChannel") && !msg.hasOwnProperty("targetUser")) || !msg.hasOwnProperty("target") || !msg.hasOwnProperty("duration") || !msg.hasOwnProperty("class") || !msg.hasOwnProperty("html")) return; if (!msg.hasOwnProperty("id") || (!msg.hasOwnProperty("targetChannel") && !msg.hasOwnProperty("targetUser"))
cl.channel.Notification(msg.targetUser || msg.targetChannel, null, null, msg.html, msg.duration, msg.target, msg.class); || !msg.hasOwnProperty("target") || !msg.hasOwnProperty("duration")) return;
let id = msg.id;
let targetChannel = msg.targetChannel;
let targetUser = msg.targetUser;
let target = msg.target;
let duration = msg.duration;
let klass;
let title;
let text;
let html;
if (msg.hasOwnProperty("class")) {
klass = msg.class;
}
if (!msg.hasOwnProperty("html")) {
if (!msg.hasOwnProperty("title") || !msg.hasOwnProperty("text")) return;
title = msg.title;
text = msg.text;
} else {
html = msg.html;
}
cl.channel.Notification(targetUser || targetChannel, title, text, html, duration, target, klass, id);
});
cl.on('user_flag', (msg, admin) => {
if (!admin) return;
if (!msg.hasOwnProperty('_id') || !msg.hasOwnProperty('key') || !msg.hasOwnProperty('value')) return;
console.log("stuff");
cl.server.connections.forEach((usr) => {
if ((usr.channel && usr.participantId && usr.user) && (usr.user._id == msg._id || (usr.participantId == msg.id))) {
if (!usr.hasOwnProperty('user')) return;
usr.user.flags[msg.key] = msg.value;
usr.user.checkFlags();
}
});
console.log(`set user flag: ${msg.key} - ${msg.value}`);
});
cl.on('clear_chat', (msg, admin) => {
if (!admin) return;
}); });
} }

View File

@ -45,61 +45,72 @@ class Quota {
this.setParams(params); this.setParams(params);
this.resetPoints(); this.resetPoints();
this.interval; this.interval;
}; }
static N_PARAMS_LOBBY = { static N_PARAMS_LOBBY = {
allowance: 200, allowance: 200,
max: 600, max: 600,
interval: 2000 interval: 2000
}; }
static N_PARAMS_NORMAL = { static N_PARAMS_NORMAL = {
allowance: 400, allowance: 400,
max: 1200, max: 1200,
interval: 2000 interval: 2000
}; }
static N_PARAMS_RIDICULOUS = { static N_PARAMS_RIDICULOUS = {
allowance: 600, allowance: 600,
max: 1800, max: 1800,
interval: 2000 interval: 2000
}; }
static PARAMS_OFFLINE = { static PARAMS_OFFLINE = {
allowance: 8000, allowance: 8000,
max: 24000, max: 24000,
maxHistLen: 3, maxHistLen: 3,
interval: 2000 interval: 2000
}; }
static PARAMS_A_NORMAL = { static PARAMS_A_NORMAL = {
allowance: 4, allowance: 4,
max: 4, max: 4,
interval: 6000 interval: 6000
}; }
static PARAMS_A_CROWNED = { static PARAMS_A_CROWNED = {
allowance:10, allowance:10,
max:10, max:10,
interval: 2000 interval: 2000
} }
static PARAMS_CH = { static PARAMS_CH = {
allowance: 1, allowance: 1,
max: 2, max: 2,
interval: 1000 interval: 1000
} }
static PARAMS_USED_A_LOT = { static PARAMS_USED_A_LOT = {
allowance:1, allowance:1,
max:1, max:1,
interval: 2000 interval: 2000
} }
static PARAMS_M = { static PARAMS_M = {
allowance:15000, allowance:15000,
max:500000, max:500000,
interval: 2000 interval: 2000
} }
getParams() { getParams() {
return { return {
m: "nq", m: "nq",
allowance: this.allowance, allowance: this.allowance,
max: this.max, max: this.max,
maxHistLen: this.maxHistLen maxHistLen: this.maxHistLen
}; }
}; }
setParams(params) { setParams(params) {
params = params || Quota.PARAMS_OFFLINE; params = params || Quota.PARAMS_OFFLINE;
var allowance = params.allowance || this.allowance || Quota.PARAMS_OFFLINE.allowance; var allowance = params.allowance || this.allowance || Quota.PARAMS_OFFLINE.allowance;
@ -118,14 +129,16 @@ class Quota {
return true; return true;
} }
return false; return false;
}; }
resetPoints() { resetPoints() {
this.points = this.max; this.points = this.max;
this.history = []; this.history = [];
for (var i = 0; i < this.maxHistLen; i++) for (var i = 0; i < this.maxHistLen; i++)
this.history.unshift(this.points); this.history.unshift(this.points);
if (this.cb) this.cb(this.points); if (this.cb) this.cb(this.points);
}; }
tick() { tick() {
// keep a brief history // keep a brief history
this.history.unshift(this.points); this.history.unshift(this.points);
@ -137,7 +150,8 @@ class Quota {
// fire callback // fire callback
if (this.cb) this.cb(this.points); if (this.cb) this.cb(this.points);
} }
}; }
spend(needed) { spend(needed) {
// check whether aggressive limitation is needed // check whether aggressive limitation is needed
var sum = 0; var sum = 0;
@ -153,7 +167,7 @@ class Quota {
if (this.cb) this.cb(this.points); // fire callback if (this.cb) this.cb(this.points); // fire callback
return true; return true;
} }
}; }
} }
module.exports = Quota module.exports = Quota

6
src/Rank.js Normal file
View File

@ -0,0 +1,6 @@
module.exports = class Rank {
constructor (name, _id) {
this.name = name;
this._id = _id;
}
}

View File

@ -1,14 +1,15 @@
const createKeccakHash = require('keccak'); const createKeccakHash = require('keccak');
const Crown = require('./Crown.js');
const Database = require('./Database.js');
const Quota = require("./Quota.js"); const Quota = require("./Quota.js");
const RoomSettings = require('./RoomSettings.js'); const RoomSettings = require('./RoomSettings.js');
class Room extends EventEmitter { class Room extends EventEmitter {
constructor(server, _id, settings) { constructor(server, _id, settings) {
super(); super();
EventEmitter.call(this);
this._id = _id; this._id = _id;
this.server = server; this.server = server;
this.crown = null; this.crown;
this.crowndropped = false; this.crowndropped = false;
this.settings = settings; this.settings = settings;
this.chatmsgs = []; this.chatmsgs = [];
@ -17,30 +18,31 @@ class Room extends EventEmitter {
this.bindEventListeners(); this.bindEventListeners();
this.server.rooms.set(_id, this); this.server.rooms.set(_id, this);
this.bans = new Map(); this.bans = new Map();
this.flags = {}
Database.getRoomSettings(this._id, (err, set) => {
if (err) {
return;
}
this.settings = set.settings;
this.chatmsgs = set.chat;
this.setData();
});
} }
join(cl, set) { //this stuff is complicated join(cl, set) { //this stuff is complicated
let otheruser = this.connections.find((a) => a.user._id == cl.user._id) let otheruser = this.connections.find((a) => a.user._id == cl.user._id)
if (!otheruser) { if (!otheruser) {
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(); cl.initParticipantQuotas();
if (((this.connections.length == 0 && Array.from(this.ppl.values()).length == 0) && this.isLobby(this._id) == false) || this.crown && (this.crown.userId == cl.user._id)) { //user that created the room, give them the crown. if (((this.connections.length == 0 && Array.from(this.ppl.values()).length == 0) && this.isLobby(this._id) == false) || this.crown && (this.crown.userId == cl.user._id)) { //user that created the room, give them the crown.
//cl.quotas.a.setParams(Quota.PARAMS_A_CROWNED); //cl.quotas.a.setParams(Quota.PARAMS_A_CROWNED);
this.crown = { this.crown = new Crown(cl.participantId, cl.user._id);
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.crowndropped = false;
this.settings = new RoomSettings(set, 'user'); this.settings = new RoomSettings(set, 'user');
@ -105,7 +107,6 @@ class Room extends EventEmitter {
if (!(otheruser.length > 1)) { if (!(otheruser.length > 1)) {
this.ppl.delete(p.participantId); this.ppl.delete(p.participantId);
this.connections.splice(this.connections.findIndex((a) => a.connectionid == p.connectionid), 1); this.connections.splice(this.connections.findIndex((a) => a.connectionid == p.connectionid), 1);
console.log(`Deleted client ${p.user.id}`);
this.sendArray([{ this.sendArray([{
m: "bye", m: "bye",
p: p.participantId p: p.participantId
@ -125,19 +126,15 @@ class Room extends EventEmitter {
if (Array.from(this.ppl.values()).length <= 0) { if (Array.from(this.ppl.values()).length <= 0) {
setTimeout(() => { setTimeout(() => {
this.destroy(); this.destroy();
}, 10000); }, 5000);
} }
this.connections.forEach((usr) => { this.connections.forEach((usr) => {
let u = this.fetchData(usr, cl); let u = this.fetchChannelData(usr, cl);
u.ppl.forEach(c => { this.server.connections.get(usr.connectionid).sendArray([u]);
c.ip = undefined;
c.server = undefined;
});
this.server.connections.get(usr.connectionid).sendArray([u])
}); });
this.server.updateRoom(this.fetchData()); this.server.updateRoom(this.fetchChannelData());
} }
updateParticipant(pid, options) { updateParticipant(pid, options) {
@ -195,11 +192,17 @@ class Room extends EventEmitter {
}); });
} }
fetchData(usr, cl) { fetchChannelData(usr, cl) {
let chppl = []; let chppl = [];
[...this.ppl.values()].forEach((a) => { [...this.ppl.values()].forEach(c => {
chppl.push(a.user); let u = {
_id: c.user._id,
name: c.user.name,
color: c.user.color,
id: c.participantId
}
chppl.push(u);
}); });
let data = { let data = {
@ -270,44 +273,13 @@ class Room extends EventEmitter {
} }
getCrownY() {
return Math.floor(Math.random() * 10000) / 100;
}
getCrownX() {
return Math.floor(Math.random() * 10000) / 100;
}
chown(id) { chown(id) {
let prsn = this.ppl.get(id); let prsn = this.ppl.get(id);
if (prsn) { if (prsn) {
this.crown = { this.crown = new Crown(id, prsn.user._id);
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; this.crowndropped = false;
} else { } else {
this.crown = { this.crown = new Crown(id, this.crown.userId);
userId: this.crown.userId,
time: Date.now(),
startPos: {
x: 50,
y: 50
},
endPos: {
x: this.getCrownX(),
y: this.getCrownY()
}
}
this.crowndropped = true; this.crowndropped = true;
} }
@ -329,7 +301,7 @@ class Room extends EventEmitter {
chat(p, msg) { chat(p, msg) {
if (msg.message.length > 512) return; if (msg.message.length > 512) return;
let filter = ["AMIGHTYWIND"]; let filter = ["AMIGHTYWIND", "CHECKLYHQ"];
let regexp = new RegExp("\\b(" + filter.join("|") + ")\\b", "i"); let regexp = new RegExp("\\b(" + filter.join("|") + ")\\b", "i");
if (regexp.test(msg.message)) return; if (regexp.test(msg.message)) return;
if (p.participantId == 0) { if (p.participantId == 0) {
@ -344,7 +316,9 @@ class Room extends EventEmitter {
}; };
message.t = Date.now(); message.t = Date.now();
this.sendArray([message]); this.sendArray([message]);
this.chatmsgs.push(message); this.chatmsgs.push(message);
this.setData();
return; return;
} }
let prsn = this.ppl.get(p.participantId); let prsn = this.ppl.get(p.participantId);
@ -352,6 +326,9 @@ class Room extends EventEmitter {
let message = {}; let message = {};
message.m = "a"; message.m = "a";
message.a = msg.message; message.a = msg.message;
if (prsn.user.hasFlag('vowels')) {
message.a = message.a.split(/[aeiouAEIOU]/).join(prsn.user.flags["vowels"]);
}
message.p = { message.p = {
color: p.user.color, color: p.user.color,
id: p.participantId, id: p.participantId,
@ -361,34 +338,46 @@ class Room extends EventEmitter {
message.t = Date.now(); message.t = Date.now();
this.sendArray([message]); this.sendArray([message]);
this.chatmsgs.push(message); this.chatmsgs.push(message);
this.setData();
} }
} }
playNote(cl, note) { playNote(cl, note) {
let vel = Math.round(cl.user.flags["volume"])/100 || undefined;
if (vel == 1) vel = undefined;
this.sendArray([{ this.sendArray([{
m: "n", m: "n",
n: note.n, n: note.n,
p: cl.participantId, p: cl.participantId,
t: note.t t: note.t,
v: vel
}], cl, true); }], cl, true);
} }
kickban(_id, ms) { kickban(_id, ms) {
ms = parseInt(ms); ms = parseInt(ms);
if (ms >= (1000 * 60 * 60)) return; if (ms >= (1000 * 60 * 60)) return;
if (ms < 0) return; if (ms < 0) return;
ms = Math.round(ms / 1000) * 1000; ms = Math.round(ms / 1000) * 1000;
let user = this.connections.find((usr) => usr.user._id == _id); let user = this.connections.find((usr) => usr.user._id == _id);
if (!user) return; if (!user) return;
let asd = true; let asd = true;
let pthatbanned = this.ppl.get(this.crown.participantId); let pthatbanned = this.ppl.get(this.crown.participantId);
this.connections.filter((usr) => usr.participantId == user.participantId).forEach((u) => { this.connections.filter((usr) => usr.participantId == user.participantId).forEach((u) => {
user.bantime = Math.floor(Math.floor(ms / 1000) / 60); user.bantime = Math.floor(Math.floor(ms / 1000) / 60);
user.bannedtime = Date.now(); user.bannedtime = Date.now();
user.msbanned = ms; user.msbanned = ms;
this.bans.set(user.user._id, user); this.bans.set(user.user._id, user);
if (this.crown && (this.crown.userId)) {
//if (this.crown && (this.crown.userId)) {
u.setChannel("test/awkward", {}); u.setChannel("test/awkward", {});
if (asd) if (asd)
this.Notification(user.user._id, this.Notification(user.user._id,
"Notice", "Notice",
@ -416,8 +405,7 @@ class Room extends EventEmitter {
"#room" "#room"
); );
} }
//}
}
}) })
} }
@ -433,6 +421,7 @@ class Room extends EventEmitter {
class: klass, class: klass,
id: id id: id
}; };
if (!id) delete obj.id; if (!id) delete obj.id;
if (!title) delete obj.title; if (!title) delete obj.title;
if (!text) delete obj.text; if (!text) delete obj.text;
@ -440,6 +429,7 @@ class Room extends EventEmitter {
if (!target) delete obj.target; if (!target) delete obj.target;
if (!duration) delete obj.duration; if (!duration) delete obj.duration;
if (!klass) delete obj.class; if (!klass) delete obj.class;
switch (who) { switch (who) {
case "all": { case "all": {
for (let con of Array.from(this.server.connections.values())) { for (let con of Array.from(this.server.connections.values())) {
@ -496,6 +486,15 @@ class Room extends EventEmitter {
} }
} }
} }
setData() {
Database.setRoomSettings(this._id, this.settings, this.chatmsgs);
}
hasFlag(flag, val) {
if (!val) return this.flags.hasOwnProperty(flag);
return this.flags.hasOwnProperty(flag) && this.flags[flag] == val;
}
} }
module.exports = Room; module.exports = Room;

View File

@ -1,14 +1,16 @@
const config = require ('../config');
class RoomSettings { class RoomSettings {
static allowedProperties = { static allowedProperties = {
color: { color: {
type: 'color', type: 'color',
default: "#9900ff", default: config.defaultRoomSettings.color,
allowedChange: true, allowedChange: true,
required: true required: true
}, },
color2: { color2: {
type: 'color2', type: 'color2',
default: "#5900bf", default: config.defaultRoomSettings.color2,
allowedChange: true, allowedChange: true,
required: false required: false
}, },
@ -39,10 +41,15 @@ class RoomSettings {
default: false, default: false,
allowedChange: true, allowedChange: true,
required: true required: true
},
"no cussing": {
type: 'boolean',
allowedChange: true,
required: false
} }
} }
constructor (set, cont) { constructor (set, context) {
Object.keys(RoomSettings.allowedProperties).forEach(key => { Object.keys(RoomSettings.allowedProperties).forEach(key => {
if (typeof(RoomSettings.allowedProperties[key].default) !== 'undefined') { if (typeof(RoomSettings.allowedProperties[key].default) !== 'undefined') {
if (this[key] !== RoomSettings.allowedProperties[key].default) { if (this[key] !== RoomSettings.allowedProperties[key].default) {
@ -63,10 +70,10 @@ class RoomSettings {
Object.keys(set).forEach(key => { Object.keys(set).forEach(key => {
if (typeof(set[key]) == 'undefined') return; if (typeof(set[key]) == 'undefined') return;
if (Object.keys(RoomSettings.allowedProperties).indexOf(key) !== -1) { if (Object.keys(RoomSettings.allowedProperties).indexOf(key) !== -1) {
if (typeof(cont) == 'undefined') { if (typeof(context) == 'undefined') {
this[key] = this.verifyPropertyType(key, set[key], RoomSettings.allowedProperties[key].type); this[key] = this.verifyPropertyType(key, set[key], RoomSettings.allowedProperties[key].type);
} else { } else {
if (cont == 'user') { if (context == 'user') {
if (RoomSettings.allowedProperties[key].allowedChange) { if (RoomSettings.allowedProperties[key].allowedChange) {
this[key] = this.verifyPropertyType(key, set[key], RoomSettings.allowedProperties[key].type); this[key] = this.verifyPropertyType(key, set[key], RoomSettings.allowedProperties[key].type);
} }

View File

@ -52,11 +52,13 @@ class Server extends EventEmitter {
this.roomlisteners = new Map(); this.roomlisteners = new Map();
this.rooms = new Map(); this.rooms = new Map();
this.specialIntervals = {};
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 = ["a", "bye", "hi", "ch", "+ls", "-ls", "m", "n", "devices", "t", "chset", "userset", "chown", "kickban", "admin message", "color", "eval", "notification"] this.legit_m = ["a", "bye", "hi", "ch", "+ls", "-ls", "m", "n", "devices", "t", "chset", "userset", "chown", "kickban", "admin message", "color", "eval", "notification", "user_flag", "room_flag", "clear_chat"]
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";
@ -68,6 +70,10 @@ class Server extends EventEmitter {
if (!data.ch.settings.visible) return; if (!data.ch.settings.visible) return;
for (let cl of Array.from(this.roomlisteners.values())) { for (let cl of Array.from(this.roomlisteners.values())) {
if (cl.destroied) {
cl = undefined;
return;
}
cl.sendArray([{ cl.sendArray([{
"m": "ls", "m": "ls",
"c": false, "c": false,

View File

@ -1,12 +1,77 @@
const Database = require("./Database"); const Database = require("./Database");
function hslToHex(h, s, l) {
l /= 100;
const a = s * Math.min(l, 1 - l) / 100;
const f = n => {
const k = (n + h / 30) % 12;
const color = l - a * Math.max(Math.min(k - 3, 9 - k, 1), -1);
return Math.round(255 * color).toString(16).padStart(2, '0');
};
return `#${f(0)}${f(8)}${f(4)}`;
}
class User { class User {
constructor(cl, data) { constructor(cl, data) {
this.server = cl.server;
this.name = data.name; this.name = data.name;
this.cl = cl;
this._id = data._id; this._id = data._id;
this.color = data.color; this.color = data.color;
this.ip = data.ip; this.flags = typeof data.flags == "object" ? data.flags : {
volume: 100,
"no chat rate limit": false,
}
}
getPublicUser() {
let t = {};
t.name = this.name;
t.color = this.color;
t._id = this._id;
return t;
}
checkFlags() {
if (typeof(this.cl.server.specialIntervals[this._id]) == 'undefined') this.cl.server.specialIntervals[this._id] = {};
if (this.hasFlag('rainbow', true)) {
if (!this.cl.server.specialIntervals[this._id].hasOwnProperty('rainbow')) {
let h = Math.floor(Math.random() * 360);
let s = 50;
let l = 50;
let hvel = 5;
let svel = 1;
let lvel = 0.5;
this.cl.server.specialIntervals[this._id].rainbow = setInterval(() => {
hvel = Math.floor(Math.random()*10);
h += hvel;
if (h > 360) h = 0;
s += svel;
if (s >= 100 || s <= 50) {
svel = -svel;
}
l += lvel;
if (l >= 75 || l <= 25) {
lvel = -lvel;
}
this.color = hslToHex(h, s, l);
Database.updateUser(this._id, this);
this.cl.channel.updateParticipant(this._id, this);
}, 1000/15);
}
} else if (this.hasFlag('rainbow', false)) {
clearInterval(this.cl.server.specialIntervals[this._id].rainbow);
}
}
hasFlag(flag, val) {
if (!val) return this.flags.hasOwnProperty(flag);
return this.flags.hasOwnProperty(flag) && this.flags[flag] == val;
} }
static updateUserModel(cl, user) { static updateUserModel(cl, user) {

8
src/UserModel.js Normal file
View File

@ -0,0 +1,8 @@
const mongoose = require('mongoose');
module.exports = mongoose.model('User', {
name: String,
_id: String,
color: String,
flags: Object
});

File diff suppressed because it is too large Load Diff