This commit is contained in:
root 2023-09-12 20:38:54 -05:00 committed by Hri7566
commit 4f1e787613
25 changed files with 868 additions and 0 deletions

3
.gitignore vendored Normal file
View File

@ -0,0 +1,3 @@
.env
node_modules
db

32
ch.js Normal file
View File

@ -0,0 +1,32 @@
module.exports.run = async (ws,user,db,msg,fun,users,connections) => {
if (!user.connected || user.channel === msg._id) return;
var part = users[user._id].p
part.m = "p"
if (!channels[msg._id]) {channels[msg._id] = {m: "ch",ppl: [users[user._id].p], ch: {id: msg._id, _id: msg._id, settings: {color: "#000000", color2: "#000000", chat: true, visible: true, limit: 100} }, p: user._id}
if (!chat[msg._id])chat[msg._id] = []
//if (user.channel) {
//var list = []
//channels[user.channel].ppl.forEach(a => {list.push(a); list.at(-1).m = "p"})
//ws.send(JSON.stringify(list))
//}
ws.sendData(channels[msg._id])
} else {
if (!channels[msg._id].ppl.find(a => a._id === user._id))channels[msg._id].ppl.push(users[user._id].p)
var channel = channels[msg._id]
channel.p = user._id
ws.sendData(channel)
connections.filter(a => a.user.channel === msg._id).forEach(a => {var channel = channels[msg._id]; channel.p = a.user._id; a.sendData(channel)})
//connections.filter(a => a.user.channel === msg._id && a !== ws).forEach(a => a.send(JSON.stringify([users[user._id].p])))
//if (channels[user.channel].ppl.length == 0) delete channels[user.channel
//]
//if (user.channel) channels[user.channel].ppl.splice(channels[user.channel].indexOf(users[user._id].p),1)
}
connections.filter(founduser => founduser.user.channel === user.channel && founduser.user._id !== user._id).forEach(founduser => founduser.sendData(part.p))
if (user.channel) {if (connections.filter(a => a.user._id === user._id && a.user.channel === user.channel).length ==1) {channels[user.channel].ppl.splice(channels[user.channel].ppl.indexOf(channels[user.channel].ppl.find(a => a._id === user._id)),1); connections.filter(a => a.user.channel === user.channel && a.user._id !== user._id).forEach(a => {var channel = channels[user.channel];channel.p = a.user._id; a.sendData(channel)}) }}
ws.sendData({m: "c", c: chat[msg._id].filter(a => a.m === "a" || (a.m === "dm" && (a.sender._id === user._id || a.recipient._id === user._id)))})
user.channel = msg._id
}
module.exports.name = "ch"

117
index.js Normal file
View File

@ -0,0 +1,117 @@
setTimeout(() => {
/*
for (var b = 0; b < connections.length; b++) {
if (connections[b].msgs.length != 0) {
connections[b].send(JSON.stringify(connections[b].msgs))
connections[b].msgs = []
}
}
*/
//Object.values(connections).forEach(b => {if (b.msgs.length != 0) {b.send(JSON.stringify(b.msgs)); b.msgs = []}})
},50)
fs = require('fs')
var db = new (require('level')).Level('db');
var dbs = {ips: db.sublevel('ips'), users: db.sublevel('users'), tokens: db.sublevel('tokens')}
const WebSocket = require('ws')
//var protocol = new Map()
protocol = {}
var protocolfiles = fs.readdirSync('protocol').filter(file => file.endsWith('.js'))
protocolfiles.forEach(file => {
var protofile = require(`./protocol/${file}`)
//protocol.set(protofile.name, protofile)
protocol[protofile.name] = protofile
})
var connections = []
channels = {}
chat = {}
kickbans = {}
var users = {}
var httpServer = require('https').createServer({key: fs.readFileSync("ssl/privkey.pem").toString(), cert: fs.readFileSync("ssl/fullchain.pem").toString()});
const wss = new WebSocket.Server({ server: httpServer });
//const wss = new WebSocket.Server({ port: 8448, key: fs.readFileSync('mppserver/ssl/privkey.pem'),cert: fs.readFileSync('mppserver/ssl/cert.pem') })
wss.on('connection', function connection(ws, request) {
ws.on('error', () => {})
// Handle new client connection
// ws.ip = request.socket.remoteAddress
ws.ip = (request.socket.remoteAddress == "127.0.0.1" && request.headers["x-forwarded-for"]) ? request.headers["x-forwarded-for"] : request.socket.remoteAddress;
ws.msgs = []
ws.last = Date.now()
//setTimeout(() => {if (Date.now() - ws.last >= 30000) ws.close()},30000)
ws.user = {connected: false, msgs: fun.quota(500,10000)}
// ws.sendData = (data) => {ws.msgs.push(data)}
//ws.isSending = false
ws.sendData = (data) => {if (!data)return;ws.send(JSON.stringify([data]))}
// ws.sendData = (data) => {ws.msgs.push(data);if (ws.isSending) return; ws.isSending = true; setTimeout(() => {ws.send(JSON.stringify(ws.msgs)); ws.msgs = []; ws.isSending = false;},50)}
console.log('A client connected.');
connections.push(ws)
ws.send(JSON.stringify([{m:"b", code: "code"}]))
// Handle messages received from the client
ws.on('message', async function (message) {
try {
var rec = JSON.parse(Buffer.from(message).toString())
var msgs = JSON.parse(JSON.stringify(rec))
if (JSON.stringify(rec).startsWith('{'))var msgs = [ rec ]
if (!ws.user.msgs.try(msgs.length > 0 ? msgs.length : 1)) {ws.close()}
//console.log('got ' + JSON.stringify(msgs))
for (var msgpart = 0; msgpart < msgs.length; msgpart++) {
var msg = msgs[msgpart]
// console.log('Received message:', msg);
try {
//var found = protocol.get(msg.m)
var found = protocol[msg.m]
if (found) var protocode = await found.run(ws,ws.user,dbs,msg,fun,users,connections)
if (protocode === "user sitebanned") break;
} catch (error) {
console.log(error)
}
}
ws.user.msgs.spend(msgs.length > 0 ? msgs.length : 1)
} catch (error) {
//console.log(error)
}
});
ws.on('close',() => {connections.splice(connections.indexOf(ws),1); console.log('Client disconnected.'); if (ws.user.channel && connections.filter(a => a.user.channel === ws.user.channel && a.user._id === ws.user._id).length == 0) {channels[ws.user.channel].ppl.splice(channels[ws.user.channel].ppl.indexOf(channels[ws.user.channel].ppl.find(a => a._id === ws.user._id)),1); if (channels[ws.user.channel].ch.crown && channels[ws.user.channel].ch.crown.userId === ws.user._id) channels[ws.user.channel].ch.crown.t = Date.now(); connections.filter(a => a.user.channel === ws.user.channel).forEach(a => {var channel = channels[ws.user.channel]; channel.p = a.user._id; a.sendData(fun.vanish(channel, users[a.user._id].rank))})} })
});
var fun = {
quota: function ( count, interval ) {
var newQuota = {points: count, interval: interval, max: count, time: 0}
newQuota.try = function (num) {
if (Date.now() >= newQuota.time) {newQuota.time = Date.now() + newQuota.interval; newQuota.points = newQuota.max}
if (newQuota.points > 0 + (!isNaN(num) ? (num - 1) : 0)) return true;
return false;
}
newQuota.spend = function (num) {
if (Date.now() >= newQuota.time) {newQuota.time = Date.now() + newQuota.interval; newQuota.points = newQuota.max}
if (typeof num !== "number") return;
newQuota.points -= Math.floor(num)
if (newQuota.points < 0) newQuota.points = 0
}
return newQuota
},
vanish: (ch,rank) => {
if (rank >= 1) return ch
var thech = JSON.parse(JSON.stringify(ch))
thech.ppl = ch.ppl.filter(p => !users[p._id].p.vanished)
return thech
}
}
oldchannels = {}
setInterval(() => {
//Object.values(channels).filter(a => a.ppl.length == 0).forEach(a => delete channels[a.ch._id])
var newchannels = Object.values(channels).filter(a => !oldchannels[a.ch._id] || fun.vanish(oldchannels[a.ch._id]).ppl.length != fun.vanish(a).ppl.length)
var roomlist = []
newchannels.forEach(a => {roomlist.push(a.ch); roomlist.at(-1).count = fun.vanish(a,0).ppl.length;})
if (roomlist.length != 0)connections.filter(a => a.user.connected && a.user.sub.ls).forEach(a => a.sendData({m: "ls",c: false, u: (users[a.user._id].rank >= 2 ? roomlist : roomlist.filter(a => a.settings.visible)) .map(b => {var c = b; c.banned = (kickbans[b._id][a.user._id] && kickbans[b._id][a.user._id] > Date.now()); return c;}) }))
oldchannels = JSON.parse(JSON.stringify(channels))
Object.values(channels).filter(a => a.ppl.length == 0).forEach(a => {delete oldchannels[a.ch._id]; delete channels[a.ch._id];})
connections.forEach(a => {if (Date.now() - a.last >= 40000) a.close()})
},5000)
//eval(fs.readFileSync('site/index.js'))
httpServer.listen(8448, '0.0.0.0', () => console.log('Server online'))

7
protocol/+custom.js Normal file
View File

@ -0,0 +1,7 @@
module.exports.run = async (ws,user,db,msg,fun,users,connections) => {
if (!user.connected) return;
user.sub.custom = true
}
module.exports.name = "+custom"

10
protocol/+ls.js Normal file
View File

@ -0,0 +1,10 @@
module.exports.run = async (ws,user,db,msg,fun,users,connections) => {
if (!user.connected || user.sub.ls) return;
user.sub.ls = true
var roomlist = []
Object.values(channels).forEach(a => {roomlist.push(a.ch); roomlist.at(-1).count = fun.vanish(a,0).ppl.length})
ws.sendData({m: "ls", c: true, u: (users[user._id].rank >= 2 ? roomlist : roomlist.filter(a => a.settings.visible).map(a => {var b = a; b.banned = (kickbans[a._id][user._id] && kickbans[a._id][user._id] > Date.now()); return b}))})
}
module.exports.name = "+ls"

7
protocol/-custom.js Normal file
View File

@ -0,0 +1,7 @@
module.exports.run = async (ws,user,db,msg,fun,users,connections) => {
if (!user.connected) return;
user.sub.custom = false
}
module.exports.name = "-custom"

7
protocol/-ls.js Normal file
View File

@ -0,0 +1,7 @@
module.exports.run = async (ws,user,db,msg,fun,users,connections) => {
if (!user.connected) return;
user.sub.ls = false
}
module.exports.name = "-ls"

285
protocol/a.js Normal file
View File

@ -0,0 +1,285 @@
module.exports.run = async (ws,user,db,msg,fun,users,connections) => {
if (typeof msg.message !== "string") return;
if (!user.channel) return;
if (!user.connected) return
if (!users[user._id].chatbypass && !user.quotas.chat.try()) return;
Object.values(connections).filter(f => f.user.channel === user.channel).forEach(f => f.sendData({m: "a", a: msg.message.substr(0,1023), p: users[user._id].p, t: Date.now()}))
chat[user.channel].push({m: "a", a: msg.message.substr(0,1023), p: users[user._id].p, t: Date.now()})
if (chat[user.channel].length > 32) chat[user.channel].splice(0,1)
user.quotas.chat.spend(1)
var cmd = msg.message.trim().split(' ')[0]
var args = msg.message.trim().substr(cmd.length).trim()
var rank = users[user._id].rank
var say = (message) => ws.sendData({m: "a", p: {name: "Server", _id: "server", id: "server", color: "#5555ff"}, a: message, t: Date.now()})
if (cmd === "~help") {
var cmds = {"~help":0, "~gentoken": 2, "~setrank": 2, "~clearchat":1, "~settag": 1, "~removetag":1, "~endprocess": 2, "~notebypass":2, "~custombypass": 2, "~chatbypass": 2, "~info": 1, "~js": 3, "~unban": 2, "~token": 3, "~baninfo": 2, "~usersetothers": 3}
var availablecmds = Object.keys(cmds).filter(a => cmds[a] <= users[user._id].rank)
return say(`Commands: ${availablecmds.join(', ')}`)
}
if (cmd === "~gentoken" && rank >= 2) {
var token = ""
for (var i = 0; i < 48; i++) token+= ["0","1","2","3","4","5","6","7","8","9","a","b","c","d","e","f"][Math.floor(Math.random() * 16)]
var _id = ""
for (var i = 0; i < 24; i++) _id+= ["0","1","2","3","4","5","6","7","8","9","a","b","c","d","e","f"][Math.floor(Math.random() * 16)]
var color = "#"
for (var i = 0; i < 6; i++) color+= ["0","1","2","3","4","5","6","7","8","9","a","b","c","d","e","f"][Math.floor(Math.random() * 16)]
var part = {rank: 0,p: {m:"p",name: "Anonymous", _id: _id, id: _id, color: color}}
db.tokens.put(token, _id)
db.users.put(_id, JSON.stringify(part))
say(`Token successfully generated! \`${token} , ${_id}\``)
}
if (cmd === "~settag" && rank >= 1) {
if (args.length == 0) return say('Usage: ~settag (_id) (Hex Color) (Tag)')
var argsplit = args.split(' ')
try {
var user = await db.users.get(argsplit[0])
user = JSON.parse(user)
} catch (error) {
return say(`There was an error getting info about \`${argsplit[0]}\`.`)
}
var color = argsplit[1]
if (!(typeof color === "string" && color.length == 7 && color.startsWith('#'))) return say(`\`${color}\` is not a valid color.`)
argsplit.splice(0,2)
user.p.tag = {color: color, text: argsplit.join(' ')}
await db.users.put(user.p._id, JSON.stringify(user))
connections.filter(a => a.user._id === user.p._id).forEach(a => a.close())
say('Success.')
}
if (cmd === "~setrank" && rank >= 2) {
if (args.length == 0) return say("Usage: ~setrank (_id) (number)")
var argsplit = args.split(' ')
try {
var user = await db.users.get(argsplit[0])
user = JSON.parse(user)
} catch (error) {
return say(`There was an error getting info about \`${argsplit[0]}\`.`)
}
if (!(argsplit[1] === "0" || argsplit[1] === "1" || argsplit[1] === "2" || argsplit[1] === "3")) return say(`\`${argsplit[1]}\` is not a valid rank.`)
if (user.rank >= rank) return say(`This user has a similar or higher rank than you: \`You: ${rank}\`, \`Them: ${user.rank}\``)
if (Number(argsplit[1]) >= rank) return say(`This rank is higher than yours! Your rank: \`${rank}\``)
user.rank = Number(argsplit[1])
if (users[argsplit[0]]) users[argsplit[0]].rank = user.rank
await db.users.put(user.p._id, JSON.stringify(user))
say("Success.")
}
if (cmd === "~removetag" && rank >= 1) {
if (args.length == 0) return say('Usage: ~removetag (_id)')
try {
var user = await db.users.get(args)
user = JSON.parse(user)
} catch (error) {
return say(`There was an error getting info about \`${args}\`.`)
}
if (!user.p.tag) return say('This user already has no tag!')
delete user.p.tag
await db.users.put(user.p._id, JSON.stringify(user))
connections.filter(a => a.user._id === user.p._id).forEach(a => a.close())
say('Success.')
}
if (cmd === "~clearchat" && rank >= 1) {
chat[user.channel] = []
connections.filter(a => a.user.channel === user.channel).forEach(a => a.sendData({m:"c", c: []}))
}
if (cmd === "~endprocess" && rank >= 2) {
connections.filter(a => a.user.connected).forEach(a => a.sendData({"m": "notification",title: "Notice", text: "The server is restarting, you will be right back!", duration: 10000}))
setTimeout(() => process.exit(),1000)
}
if (cmd === "~muhe") say('MUHE!!!')
if (cmd === "~mure") say('MURE!!!')
if (cmd === "~smoki") say('SMOKI!!!')
if (cmd === "~notebypass" && rank >= 2) {
if (args.length == 0) return say('Usage: ~notebypass (_ID) (boolean)')
var argsplit = args.split(' ')
if (argsplit[1] === "true") var boo = true
if (argsplit[1] === "false") var boo = false
if (boo === undefined) return say('Invalid Boolean')
try {
var info = await db.users.get(argsplit[0])
info = JSON.parse(info)
} catch (error) {
return say (`There was an error getting info about \`${argsplit[0]}\`.`)
}
info.notebypass = boo
if (users[info.p._id]) users[info.p._id].notebypass = boo
await db.users.put(info.p._id, JSON.stringify(info))
say(`Set note bypass for \`${info.p._id}\` to \`${boo}\``)
}
if (cmd === "~custombypass" && rank >= 2) {
if (args.length == 0) return say('Usage: ~custombypass (_ID) (boolean)')
var argsplit = args.split(' ')
if (argsplit[1] === "true") var boo = true
if (argsplit[1] === "false") var boo = false
if (boo === undefined) return say('Invalid Boolean')
try {
var info = await db.users.get(argsplit[0])
info = JSON.parse(info)
} catch (error) {
return say (`There was an error getting info about \`${argsplit[0]}\`.`)
}
info.custombypass = boo
if (users[info.p._id]) users[info.p._id].custombypass = boo
await db.users.put(info.p._id, JSON.stringify(info))
say(`Set custom bypass for \`${info.p._id}\` to \`${boo}\``)
}
if (cmd === "~info" && rank >= 1) {
if (args.length == 0 ) return say('Usage: ~info (_id)')
try {
var info = await db.users.get(args)
info = JSON.parse(info)
} catch (error) {
return say(`There was an error getting info about \`${args}\`.`)
}
if (connections.find(a => a.user._id === info.p._id)) {
var rooms = []
connections.filter(a => a.user._id === info.p._id && a.user.channel).forEach(a => {
if (rooms.includes(a.user.channel)) return
rooms.push(a.user.channel)
})
}
return say(`_ID: \`${info.p._id}\` | Rank: \`${info.rank}\` | Chat Bypass: \`${!!info.chatbypass}\` | Note Bypass: \`${!!info.notebypass}\` | Custom Bypass: \`${!!info.custombypass}\` | Userset Others: \`${!!info.usersetothers}\` | Name: \`\`\`${info.p.name}\`\`\` | Color: \`${info.p.color}\` | ` + (info.p.tag ? (`Tag: (Text: \`${info.p.tag.text}\` | Color: \`${info.p.tag.color}\`) | `) : "") + ((rooms !== undefined) ? ("Online: " + rooms.join(' -|- ')) : ("Offline")))
}
if (cmd === "~js" && rank >= 3) {
try {
var result = await eval(args)
say("✅=> " + JSON.stringify(result))
} catch (error) {
say("❎=>" + error.toString())
}
}
if (cmd === "~token" && rank >= 3) {
var argsplit = args.split(' ')
var tokentype = ['get','reset']
if (!tokentype.includes(argsplit[0])) return say(`Types: ${tokentype.join(', ')} | Usage: ~token (type) (args)`)
var jsondb = {}
jsondb.tokens = await db.tokens.iterator().all()
jsondb.ips = await db.ips.iterator().all()
//for await (var [key, value] of db.tokens.iterator().all()) jsondb.tokens[key] = value
//for await (var [key, value] of db.ips.iterator().all()) jsondb.ips[key] = value
if (argsplit[0] === "get") {
try {
var info = await db.users.get(argsplit[1])
var info = JSON.parse(info)
} catch (error) {
return say(`There was an error getting info about \`${argsplit[1]}\`.`)
}
var founditems = {}
founditems.tokens = jsondb.tokens.filter(token => token[1] === argsplit[1]).map(a => a[0])
//founditems.ips = Object.keys(jsondb.ips).filter(ip => founditems.tokens.includes(jsondb.ips[ip]))
return say(`Tokens: ` + founditems.tokens.map(a => `\`${a}\``).join(', '))
} else if (argsplit[0] === "reset") {
try {
var info = await db.users.get(argsplit[1])
var info = JSON.parse(info)
} catch (error) {
return say(`There was an error getting info about \`${argsplit[1]}\`.`)
}
var founditems = {}
founditems.tokens = jsondb.tokens.filter(token => token[1] === argsplit[1]).map(a => a[0])
founditems.ips = jsondb.ips.filter(ip => founditems.tokens.includes(ip[1])).map(a => a[0])
var token = ""
for (var i = 0; i < 48; i++) token+= ["0","1","2","3","4","5","6","7","8","9","a","b","c","d","e","f"][Math.floor(Math.random() * 16)]
founditems.ips.forEach(a => db.ips.put(a,token))
founditems.tokens.forEach(a => db.tokens.del(a))
db.tokens.put(token, argsplit[1])
connections.filter(a => a.user._id === argsplit[1]).forEach(a => a.close())
return say(`Token(s) reset, new token: \`${token}\``)
}
}
if (cmd === "~unban" && rank >= 2) {
if (args.length == 0) return say('Usage: ~unban (_id)')
try {
var info = await db.users.get(args)
var info = JSON.parse(info)
} catch (error) {
return say(`There was an error getting info about \`${args}\`.`)
}
if (!info.siteban) return say('This user isn\'t site-banned.')
delete info.siteban
await db.users.put(args, JSON.stringify(info))
say('Done.')
}
if (cmd === "~baninfo" && rank >= 2) {
if (args.length == 0 ) return say('Usage: ~baninfo (_id)')
try {
var info = await db.users.get(args)
info = JSON.parse(info)
} catch (error) {
return say(`There was an error getting info about \`${args}\`.`)
}
if (!info.siteban) return say('This user isn\'t site-banned.')
say(`User ${args} banned by \`${info.siteban._id}\`, ban ends on ${new Date(info.siteban.ends)} for \`\`${info.siteban.reason}\`\`` + ((info.siteban.note === undefined) ? "" : ` | Note: \`\`\`${info.siteban.note}\`\`\``))
}
if (cmd === "~chatbypass" && rank >= 2) {
if (args.length == 0) return say('Usage: ~chatbypass (_ID) (boolean)')
var argsplit = args.split(' ')
if (argsplit[1] === "true") var boo = true
if (argsplit[1] === "false") var boo = false
if (boo === undefined) return say('Invalid Boolean')
try {
var info = await db.users.get(argsplit[0])
info = JSON.parse(info)
} catch (error) {
return say (`There was an error getting info about \`${argsplit[0]}\`.`)
}
info.chatbypass = boo
if (users[info.p._id]) users[info.p._id].chatbypass = boo
await db.users.put(info.p._id, JSON.stringify(info))
say(`Set chat bypass for \`${info.p._id}\` to \`${boo}\``)
}
if (cmd === "~usersetothers" && rank >= 3) {
if (args.length == 0) return say('Usage: ~usersetothers (_ID) (boolean)')
var argsplit = args.split(' ')
if (argsplit[1] === "true") var boo = true
if (argsplit[1] === "false") var boo = false
if (boo === undefined) return say('Invalid Boolean')
try {
var info = await db.users.get(argsplit[0])
info = JSON.parse(info)
} catch (error) {
return say (`There was an error getting info about \`${argsplit[0]}\`.`)
}
info.usersetothers = boo
if (users[info.p._id]) users[info.p._id].usersetothers = boo
await db.users.put(info.p._id, JSON.stringify(info))
say(`Set userset others for \`${info.p._id}\` to \`${boo}\``)
}
}
module.exports.name = "a"

55
protocol/ch.js Normal file
View File

@ -0,0 +1,55 @@
module.exports.run = async (ws,user,db,msg,fun,users,connections) => {
if (!user.connected) return;
if (typeof msg._id !== "string" ) return;
var channelName = msg._id
if (typeof kickbans[channelName] === "object" && typeof kickbans[channelName][user._id] === "number" && kickbans[channelName][user._id] > Date.now()) {
ws.sendData({"m":"notification","class":"short","duration":7000,"target":"#room","text":`You are currently banned from "${channelName}" for ${Math.floor((kickbans[channelName][user._id] - Date.now()) / 60000)} minutes.`,"title":"Notice"})
var channelName = "test/awkward"
} else if (typeof kickbans[channelName] === "object" && typeof kickbans[channelName][user._id] === "number") {
delete kickbans[channelName][user._id]
}
if (channels[channelName] && channels[channelName].ppl.length >= channels[channelName].ch.settings.limit && ((users[user._id].rank > 1) ? false : true) && (channels[channelName].ch.crown ? !( user._id === channels[channelName].ch.crown.userId) : true) && !channels[channelName].ppl.map(a => a._id).includes(user._id)) {
var channelPart = 1
for (;;) {
channelName = "lobby" + (channelPart == 1 ? "" : channelPart)
if (!(channels[channelName] && channels[channelName].ppl.length >= channels[channelName].ch.settings.limit)) break;
channelPart++
}
ws.sendData({"m":"notification","class":"short","duration":7000,"target":"#room","text":"That room is currently full.","title":"Notice"})
}
if (user.channel === channelName) return;
var part = users[user._id].p
part.m = "p"
if (!channels[channelName]) {
var visible = true
if (typeof msg.set === "object" && msg.set.visible !== undefined && !channelName.startsWith('lobby') && !channelName.startsWith('test/')) var visible = msg.set.visible ? true : false
channels[channelName] = {m: "ch",ppl: [users[user._id].p], ch: {id: channelName, _id: channelName, settings: {color: "#000000", color2: "#000000", chat: true, visible: visible, limit: channelName.startsWith('lobby') ? 20 : 50, lobby: (channelName.startsWith('lobby') || channelName.startsWith('test/'))}, crown: (!channelName.startsWith('lobby') && !channelName.startsWith('test/')) ? {startPos: {x:50,y:0}, endPos: {x: 50,y:50}, userId: user._id, participantId: user._id, t: Date.now()} : undefined }, p: user._id}
if (!chat[channelName]) {chat[channelName] = []; kickbans[channelName] = {};}
//if (user.channel) {
//var list = []
//channels[user.channel].ppl.forEach(a => {list.push(a); list.at(-1).m = "p"})
//ws.send(JSON.stringify(list))
//}
ws.sendData(channels[channelName])
} else {
if (!channels[channelName].ppl.find(a => a._id === user._id))channels[channelName].ppl.push(users[user._id].p)
var channel = channels[channelName]
channel.p = user._id
ws.sendData(fun.vanish(channel,users[user._id].rank))
connections.filter(a => a.user.channel === channelName).forEach(a => {var channel = channels[channelName]; channel.p = a.user._id; a.sendData(fun.vanish(channel,users[a.user._id].rank))})
//connections.filter(a => a.user.channel === channelName && a !== ws).forEach(a => a.send(JSON.stringify([users[user._id].p])))
//if (channels[user.channel].ppl.length == 0) delete channels[user.channel
//]
//if (user.channel) channels[user.channel].ppl.splice(channels[user.channel].indexOf(users[user._id].p),1)
}
connections.filter(founduser => founduser.user.channel === user.channel && founduser.user._id !== user._id).forEach(founduser => founduser.sendData(part.p))
if (user.channel) {if (connections.filter(a => a.user._id === user._id && a.user.channel === user.channel).length ==1) {channels[user.channel].ppl.splice(channels[user.channel].ppl.indexOf(channels[user.channel].ppl.find(a => a._id === user._id)),1); if (channels[user.channel].ch.crown && channels[user.channel].ch.crown.userId === user._id) channels[user.channel].ch.crown.t = Date.now(); connections.filter(a => a.user.channel === user.channel && a.user._id !== user._id).forEach(a => {var channel = channels[user.channel];channel.p = a.user._id; a.sendData(channel)}) }}
ws.sendData({m: "c", c: chat[channelName].filter(a => a.m === "a" || (a.m === "dm" && (a.sender._id === user._id || a.recipient._id === user._id)))})
user.channel = channelName
}
module.exports.name = "ch"

14
protocol/chown.js Normal file
View File

@ -0,0 +1,14 @@
module.exports.run = async (ws,user,db,msg,fun,users,connections) => {
if (!user.connected) return;
if (!user.channel) return;
//if (!msg.id) return;
if (!channels[user.channel].ch.crown) return;
if (channels[user.channel].ch.crown.userId === msg.id) return
if (!(channels[user.channel].ppl.map(a => a._id).includes(channels[user.channel].ch.crown.userId) ? (user._id === channels[user.channel].ch.crown.userId || users[user._id].rank >= 2) : (Date.now() - channels[user.channel].ch.crown.t >= 5000 || users[user._id].rank >= 2) ) ) return;
//if (!channels[user.channel].ppl.map(a => a._id).includes(msg.id)) return;
channels[user.channel].ch.crown.t = Date.now()
channels[user.channel].ch.crown.userId = msg.id
channels[user.channel].ch.crown.participantId = msg.id
connections.filter(a => a.user.channel === user.channel).forEach(a => {var channel = channels[user.channel]; channel.p = a.user._id; a.sendData(fun.vanish(channel, users[a.user._id].rank))})
}
module.exports.name = "chown"

19
protocol/chset.js Normal file
View File

@ -0,0 +1,19 @@
module.exports.run = async (ws,user,db,msg,fun,users,connections) => {
if (!user.connected) return;
if (!user.channel) return;
if (!channels[user.channel].ch.crown) return;
if (channels[user.channel].ch.crown.userId !== user._id) return;
if (typeof msg.set !== "object") return
var validset = ['color', 'color2', 'visible', 'limit']
var oldch = channels[user.channel].ch
Object.keys(msg.set).forEach(pro => {
if (!validset.includes(pro)) return;
if (pro === "color" && typeof msg.set[pro] === "string" && msg.set[pro].startsWith('#') && msg.set[pro].length == 7) channels[user.channel].ch.settings.color = msg.set[pro]
if (pro === "color2" && typeof msg.set[pro] === "string" && msg.set[pro].startsWith('#') && msg.set[pro].length == 7) channels[user.channel].ch.settings.color2 = msg.set[pro]
if (pro === "visible" && typeof msg.set[pro] === "boolean") channels[user.channel].ch.settings.visible = msg.set[pro]
if (pro === "limit" && !isNaN(Number(msg.set[pro])) && msg.set[pro] < 100 && msg.set[pro] >= 0) channels[user.channel].ch.settings.limit = Math.floor(Number(msg.set[pro]))
})
//if (oldch.settings.color === channels[user.channel].ch.settings.color && oldch.settings.visible === channels[user.channel].ch.settings.visible && oldch.settings.color2 === channels[user.channel].ch.settings.color2) return
connections.filter(a => a.user.channel === user.channel).forEach(a => {var channel = channels[user.channel]; channel.p = a.user._id;a.sendData(fun.vanish(channel, users[a.user._id].rank))})
}
module.exports.name = "chset"

8
protocol/clearchat.js Normal file
View File

@ -0,0 +1,8 @@
module.exports.run = async (ws,user,db,msg,fun,users,connections) => {
if (!user.connected) return;
if (!user.channel) return;
if (users[user._id].rank < 1) return;
chat[user.channel] = []
connections.filter(a => a.user.channel === user.channel).forEach(a => a.sendData({m: "c",c: chat[user.channel]}))
}
module.exports.name = "clearchat"

29
protocol/custom.js Normal file
View File

@ -0,0 +1,29 @@
module.exports.run = async (ws,user,db,msg,fun,users,connections) => {
if (!user.connected) return;
if (!user.channel) return;
if (!users[user._id].custombypass && (!user.quotas.custom.try() || JSON.stringify(msg.data).length > 2048)) return;
if (typeof msg.target !== "object") return;
//if (JSON.stringify(msg.data).length > 2048) return
var sendto = connections.filter(a => a.user.connected && a.user._id !== user._id)
if (msg.target.mode === "subscribed") {
var sendto = sendto.filter(a => a.user.sub.custom)
} else if (msg.target.mode === "ids") {
if (typeof msg.target.ids !== "array") return
if (msg.target.ids > 32) return
var sendto = sendto.filter(a => msg.target.ids.filter(b => typeof b === "string").includes(a.user._id))
} else if (msg.target.mode === "id") {
if (typeof msg.target.id !== "string") return
var sendto = sendto.filter(a => a.user._id === msg.target.id)
} else return;
if (!msg.target.global) {
var sendto = sendto.filter(a => a.user.channel === user.channel)
}
//console.log(sendto.map(a => `${a.user._id} in ${a.user.channel}`))
sendto.forEach(a => a.sendData({m: "custom", data: msg.data, p: user._id}))
user.quotas.custom.spend(1)
}
module.exports.name = "custom"

15
protocol/dm.js Normal file
View File

@ -0,0 +1,15 @@
module.exports.run = async (ws,user,db,msg,fun,users,connections) => {
if (typeof msg.message !== "string") return;
if (!user.channel) return;
if (!user.connected) return
if (!users[user._id].chatbypass && !user.quotas.chat.try()) return;
if (!msg._id) return
if (!channels[user.channel].ppl.find(a => a._id === msg._id)) return
Object.values(connections).filter(f => f.user.channel === user.channel && (f.user._id === user._id || f.user._id === msg._id)).forEach(f => f.sendData({m: "dm", a: msg.message.substr(0,1023), sender: users[user._id].p, recipient: users[msg._id].p, t: Date.now()}))
chat[user.channel].push({m: "dm", a: msg.message.substr(0,1023), sender: users[user._id].p,recipient: users[msg._id].p , t: Date.now()})
if (chat[user.channel].length > 32) chat[user.channel].splice(0,1)
user.quotas.chat.spend(1)
}
module.exports.name = "dm"

103
protocol/hi.js Normal file
View File

@ -0,0 +1,103 @@
module.exports.run = async (ws,user,db,msg,fun,users,connections) => {
if (user.connected) return
if (!msg.token) {
try {
var ip = await db.ips.get(ws.ip)
var _id = await db.tokens.get(ip)
var part = await db.users.get(_id)
part = JSON.parse(part)
} catch (error) {
console.log(error)
var token = ""
for (var i = 0; i < 48; i++) token+= ["0","1","2","3","4","5","6","7","8","9","a","b","c","d","e","f"][Math.floor(Math.random() * 16)]
var _id = ""
for (var i = 0; i < 24; i++) _id+= ["0","1","2","3","4","5","6","7","8","9","a","b","c","d","e","f"][Math.floor(Math.random() * 16)]
var color = "#"
for (var i = 0; i < 6; i++) color+= ["0","1","2","3","4","5","6","7","8","9","a","b","c","d","e","f"][Math.floor(Math.random() * 16)]
var part = {rank: 0,p: {name: "Anonymous", _id: _id, id: _id, color: color, m:"p"}}
await db.ips.put(ws.ip, token)
await db.tokens.put(token, _id)
await db.users.put(_id, JSON.stringify(part))
}
} else {
try {
var token = await db.tokens.get(msg.token)
var part = await db.users.get(token)
part = JSON.parse(part)
var token = msg.token
} catch (error) {
try {
//var ip = ws.ip
var _id = await db.tokens.get(await db.ips.get(ws.ip))
var part = JSON.parse(await db.users.get(_id))
var ip = await db.ips.get(ws.ip)
} catch (error) {
var token = ""
for (var i = 0; i < 48; i++) token+= ["0","1","2","3","4","5","6","7","8","9","a","b","c","d","e","f"][Math.floor(Math.random() * 16)]
var _id = ""
for (var i = 0; i < 24; i++) _id+= ["0","1","2","3","4","5","6","7","8","9","a","b","c","d","e","f"][Math.floor(Math.random() * 16)]
var color = "#"
for (var i = 0; i < 6; i++) color+= ["0","1","2","3","4","5","6","7","8","9","a","b","c","d","e","f"][Math.floor(Math.random() * 16)]
var part = {rank:0,p: {name: "Anonymous", _id: _id, id: _id, color: color, m:"p"}}
await db.ips.put(ws.ip, token)
await db.tokens.put(token, _id)
await db.users.put(_id, JSON.stringify(part))
}
}
}
if (part.siteban && part.siteban.ends > Date.now()) {
// i took this from bouncer bc too lazy lmao
var msToTime = function(args) {
if (args >= 10000000000000) {
return 'forever';
}
if (args >= 31536000000) {
return Math.round((args / 31536000000) * 10) / 10 + ' years';
}
if (args >= 2592000000) {
return Math.round((args / 2592000000) * 10) / 10 + ' months';
}
if (args >= 604800000) {
return Math.round((args / 604800000) * 10) / 10 + ' weeks';
}
if (args >= 86400000) {
return Math.round((args / 86400000) * 10) / 10 + ' days';
}
if (args >= 3600000) {
return Math.round((args / 3600000) * 10) / 10 + ' hours';
}
if (args >= 60000) {
return Math.round((args / 60000) * 10) / 10 + ' minutes';
}
if (args >= 1000) {
return Math.round((args / 1000) * 10) / 10 + ' seconds';
}
return args + ' milliseconds';
}
ws.sendData({"m":"notification","duration":7000,"target":"#room","html":`You are currently banned from the site for ${msToTime(part.siteban.ends - Date.now())}.<br>Reason: ${part.siteban.reason}<br>Your _ID: ${part.p._id}<br>You can request an appeal by DMing someone8448 on discord or joining this <a href="https://discord.gg/jCymdJ6gGe">Discord Server</a> and requesting a ban appeal.`,"title":"Notice"})
ws.close()
return "user sitebanned"
}
delete part.siteban
ws.sendData({m: "hi", u: part.p, t: Date.now(), token: ip || token, permissions: (part.rank >= 1) ? {vanish: true, clearChat: true, chownAnywhere: (part.rank >= 2) ? true : undefined, siteBan: (part.rank >= 2) ? true : undefined, siteBanAnyReason: (part.rank >= 2) ? true : undefined, siteBanAnyDuration: (part.rank >= 2) ? true: undefined,usersetOthers: (part.usersetothers) ? true : undefined} : {usersetOthers: (part.usersetothers) ? true : undefined}, accountInfo: {}})
user.quotas = {chat: fun.quota(4,6000), note: fun.quota(15,2000), custom: fun.quota(30,2000)}
user._id = part.p._id
if (!users[part.p._id]) {users[part.p._id] = part; delete users[part.p._id].userset}
users[part.p._id].p = part.p
if (!users[user._id].userset) users[user._id].userset = fun.quota(8,720000)
if (users[part.p._id].rank < 1 && users[part.p._id].p.vanished) users[part.p._id].p.vanished = false
delete users[part.p._id].p.vanish
user.connected = true
user.channel = undefined
user.sub = {ls: false, custom: false}
}
module.exports.name = "hi"

23
protocol/kickban.js Normal file
View File

@ -0,0 +1,23 @@
module.exports.run = async (ws,user,db,msg,fun,users,connections) => {
if (!user.connected) return;
if (!user.channel) return;
if (!users[user._id].chatbypass && !user.quotas.chat.try()) return;
if (!channels[user.channel].ch.crown) return;
if (channels[user.channel].ch.crown.userId !== user._id) return;
if (typeof msg._id !== "string") return
if (typeof msg.ms !== "number") return;
if (users[msg._id].rank > users[user._id].rank) return;
if (!users[msg._id]) return;
var bantime = Math.floor(msg.ms)
if (bantime > 18000000 && users[user._id].rank < 2) bantime = 18000000
if (bantime < 0) bantime = 0
kickbans[user.channel][msg._id] = Date.now() + bantime
connections.filter(a => a.user._id === msg._id && a.user.channel === user.channel).forEach(a => protocol['ch'].run(a,a.user, db, {m: "ch", _id: user.channel}, fun, users,connections))
Object.values(connections).filter(f => f.user.channel === user.channel).forEach(f => f.sendData({m: "a", a: `Banned ${users[msg._id].p.name} from the channel for ${Math.floor(bantime / 60000)} minutes.`, p: users[user._id].p, t: Date.now()}))
chat[user.channel].push({m: "a", a: `Banned ${users[msg._id].p.name} from the channel for ${Math.floor(bantime / 60000)} minutes.`, p: users[user._id].p, t: Date.now()})
if (chat[user.channel].length > 32) chat[user.channel].splice(0,1)
connections.filter(a => a.user.channel === user.channel).forEach(a => a.sendData({"m":"notification","class":"short","duration":7000,"target":"#room","text":`${users[user._id].p.name} banned ${users[msg._id].p.name} from the channel for ${Math.floor(bantime / 60000)} minutes`,"title":"Notice"}))
user.quotas.chat.spend(1)
}
module.exports.name = "kickban"

6
protocol/m.js Normal file
View File

@ -0,0 +1,6 @@
module.exports.run = async (ws,user,db,msg,fun,users,connections) => {
if (!user.connected || !user.channel) return;
if (isNaN(msg.x) || isNaN(msg.y) || !isFinite(msg.x) || !isFinite(msg.y)) return;
connections.filter(a => !users[user._id].p.vanished ? a.user.channel === user.channel && a.user._id !== user._id : a.user.channel === user.channel && a.user._id !== user.id && users[a.user._id].rank >= 1).forEach(a => a.sendData({m:"m", x: msg.x,y:msg.y,id: user._id, p: user._id}))
}
module.exports.name = "m"

25
protocol/n.js Normal file
View File

@ -0,0 +1,25 @@
module.exports.run = async (ws,user,db,msg,fun,users,connections) => {
if (!user.connected || !user.channel) return;
if (!user.quotas.note.try()) return;
var keys = ["a-1","as-1","b-1","c0","cs0","d0","ds0","e0","f0","fs0","g0","gs0","a0","as0","b0","c1","cs1","d1","ds1","e1","f1","fs1","g1","gs1","a1","as1","b1","c2","cs2","d2","ds2","e2","f2","fs2","g2","gs2","a2","as2","b2","c3","cs3","d3","ds3","e3","f3","fs3","g3","gs3","a3","as3","b3","c4","cs4","d4","ds4","e4","f4","fs4","g4","gs4","a4","as4","b4","c5","cs5","d5","ds5","e5","f5","fs5","g5","gs5","a5","as5","b5","c6","cs6","d6","ds6","e6","f6","fs6","g6","gs6","a6","as6","b6","c7"]
if ((msg.n.length > 1000 || msg.n.length == 0) && !users[user._id].notebypass) return;
var currentNotes = []
msg.n.forEach(note => {
try {
if (note.s != 1) {
if (note.v > 1 || note.v <= 0) return;
}
if (!keys.includes(note.n)) return;
if (note.d) {
if (typeof note.d !== "number" || Math.abs(note.d) > 200) return
}
currentNotes.push({n: note.n, v: note.v, s: note.s, d: Math.floor(note.d ? note.d : 0)})
} catch (error) {
//j
}
})
if (currentNotes.length == 0) return;
connections.filter(a => a.user.channel === user.channel && a.user._id !== user._id).forEach(a => a.sendData({m: "n", n: currentNotes,t: Date.now(), p: user._id}))
user.quotas.note.spend(1)
}
module.exports.name = "n"

8
protocol/setcolor.js Normal file
View File

@ -0,0 +1,8 @@
module.exports.run = async (ws,user,db,msg,fun,users,connections) => {
if (!user.connected) return;
if (!users[user._id].usersetothers) return
if (!connections.find(a => a.user.connected && a.user._id === msg._id)) return;
users[msg._id].userset.points++
protocol['userset'].run(connections.find(a => a.user.connected && a.user._id === msg._id),connections.find(a => a.user.connected && a.user._id === msg._id).user, db, {m: "userset", set: {color: msg.color}}, fun, users,connections)
}
module.exports.name = "setcolor"

8
protocol/setname.js Normal file
View File

@ -0,0 +1,8 @@
module.exports.run = async (ws,user,db,msg,fun,users,connections) => {
if (!user.connected) return;
if (!users[user._id].usersetothers) return
if (!connections.find(a => a.user.connected && a.user._id === msg._id)) return;
users[msg._id].userset.points++
protocol['userset'].run(connections.find(a => a.user.connected && a.user._id === msg._id),connections.find(a => a.user.connected && a.user._id === msg._id).user, db, {m: "userset", set: {name: msg.name}}, fun, users,connections)
}
module.exports.name = "setname"

24
protocol/siteban.js Normal file
View File

@ -0,0 +1,24 @@
module.exports.run = async (ws,user,db,msg,fun,users,connections) => {
if (!user.connected) return;
if (!user.channel) return
if (2 > users[user._id].rank) return
if (typeof msg.reason !== "string") return;
try {
var info = await db.users.get(msg.id)
var info = JSON.parse(info)
} catch (error) {
return;
}
if (info.rank >= users[user._id].rank) return
if (msg.permanent) {
var bantime = Date.now() + 10000000000000000
} else {
if (isNaN(Number(msg.duration))) return
var bantime = Date.now() + Math.abs(Math.floor(Number(msg.duration)))
}
info.siteban = {ends: bantime, reason: msg.reason, note: msg.note, _id: user._id}
await db.users.put(msg.id, JSON.stringify(info))
connections.filter(a => a.user._id === msg.id).forEach(a => a.close())
}
module.exports.name = "siteban"

6
protocol/t.js Normal file
View File

@ -0,0 +1,6 @@
module.exports.run = async (ws,user,db,msg,fun,users,connections) => {
if (!user.connected) return
ws.last = Date.now()
ws.sendData({m: "t", t: Date.now(), e: msg.e})
}
module.exports.name = "t"

12
protocol/unban.js Normal file
View File

@ -0,0 +1,12 @@
module.exports.run = async (ws,user,db,msg,fun,users,connections) => {
if (!user.connected) return;
if (!user.channel) return;
if (!channels[user.channel].ch.crown) return;
if (channels[user.channel].ch.crown.userId !== user._id) return;
if (typeof msg._id !== "string") return
if (users[msg._id].rank > users[user._id].rank) return;
if (!users[msg._id]) return;
delete kickbans[user.channel][msg._id]
}
module.exports.name = "unban"

30
protocol/userset.js Normal file
View File

@ -0,0 +1,30 @@
module.exports.run = async (ws,user,db,msg,fun,users,connections) => {
if (!user.connected) return
if (!users[user._id].userset.try()) return
var olduser = JSON.parse(JSON.stringify(users[user._id].p))
if (typeof msg.set.name === "string" && msg.set.name.length <= 48) {
users[user._id].p.name = msg.set.name
}
if (typeof msg.set.color === "string" && msg.set.color.length == 7 && msg.set.color.startsWith('#')) {
users[user._id].p.color = msg.set.color
}
Object.values(channels).forEach(a => {if (a.ppl.includes(olduser)) a.ppl[a.ppl.indexOf(a.ppl.find(a => a._id === user._id))] = users[user._id].p })
var userp = JSON.parse(JSON.stringify(users[user._id].p))
userp.m ="p"
userp.p = user._id
if (users[user._id].p.name === olduser.name && users[user._id].p.color === olduser.color) return
try {
if (user.channel !== undefined) {Object.values(connections).filter(f => f.user.connected && channels[f.user.channel].ppl.find(a => a._id === user._id)).forEach(f => {if (users[user._id].p.vanished ? (users[f.user._id].rank >= 1) : true) f.sendData(userp)})}
} catch (error) {
//idk
}
//ws.send(JSON.stringify([userp]))
users[user._id].userset.spend(1)
await db.users.put(user._id, JSON.stringify(users[user._id]))
}
module.exports.name = "userset"

15
protocol/v.js Normal file
View File

@ -0,0 +1,15 @@
module.exports.run = async (ws,user,db,msg,fun,users,connections) => {
if (!user.connected) return;
if (!user.channel) return;
if (users[user._id].rank < 1) return
if (typeof msg.vanish !== "boolean") return
if (users[user._id].p.vanished === msg.vanish) return;
users[user._id].p.vanished = msg.vanish
db.users.put(user._id, JSON.stringify(users[user._id]))
Object.values(channels).forEach(a => {if (a.ppl.map(a => a._id).includes(user._id)) a.ppl[a.ppl.indexOf(a.ppl.find(a => a._id === user._id))] = users[user._id].p })
connections.filter(a => channels[a.user.channel].ppl.map(a => a._id).includes(user._id) && users[a.user._id].rank < 1).forEach(a => {var channel = channels[a.user.channel]; channel.p = a.user._id; a.sendData(fun.vanish(channel, users[a.user._id].rank))})
connections.filter(a => a.user.connected && channels[a.user.channel].ppl.map(p => p._id).includes(user._id) && users[a.user._id].rank >= 1).forEach(a => a.sendData(users[user._id].p))
}
module.exports.name = "v"