mirror of
https://github.com/Auties00/Reboot-Launcher.git
synced 2026-01-13 03:02:22 +01:00
275 lines
12 KiB
JavaScript
Vendored
275 lines
12 KiB
JavaScript
Vendored
const WebSocket = require("ws").Server;
|
|
const XMLBuilder = require("xmlbuilder");
|
|
const XMLParser = require("xml-parser");
|
|
|
|
const functions = require("./../structure/functions.js");
|
|
const matchmaker = require("./matchmaker.js");
|
|
|
|
const port = 80;
|
|
|
|
const wss = new WebSocket({ port: port }, () => console.log("XMPP and Matchmaker started listening on port", port));
|
|
wss.on("error", (err) => {
|
|
console.log("XMPP and Matchmaker \x1b[31mFAILED\x1b[0m to start hosting.");
|
|
})
|
|
|
|
|
|
global.Clients = [];
|
|
|
|
wss.on('connection', async (ws) => {
|
|
ws.on('error', () => {});
|
|
|
|
if (ws.protocol.toLowerCase() != "xmpp") return matchmaker(ws);
|
|
|
|
var accountId = "";
|
|
var jid = "";
|
|
var id = "";
|
|
var ID = functions.MakeID();
|
|
var Authenticated = false;
|
|
|
|
ws.on('message', async (message) => {
|
|
if (Buffer.isBuffer(message)) message = message.toString();
|
|
const msg = XMLParser(message);
|
|
if (!msg.root) return Error(ws);
|
|
|
|
switch (msg.root.name) {
|
|
case "open":
|
|
ws.send(XMLBuilder.create("open")
|
|
.attribute("xmlns", "urn:ietf:params:xml:ns:xmpp-framing")
|
|
.attribute("from", "prod.ol.epicgames.com")
|
|
.attribute("id", ID)
|
|
.attribute("version", "1.0")
|
|
.attribute("xml:lang", "en").toString())
|
|
|
|
if (Authenticated == true) {
|
|
ws.send(XMLBuilder.create("stream:features").attribute("xmlns:stream", "http://etherx.jabber.org/streams")
|
|
.element("ver").attribute("xmlns", "urn:xmpp:features:rosterver").up()
|
|
.element("starttls").attribute("xmlns", "urn:ietf:params:xml:ns:xmpp-tls").up()
|
|
.element("bind").attribute("xmlns", "urn:ietf:params:xml:ns:xmpp-bind").up()
|
|
.element("compression").attribute("xmlns", "http://jabber.org/features/compress")
|
|
.element("method", "zlib").up().up()
|
|
.element("session").attribute("xmlns", "urn:ietf:params:xml:ns:xmpp-session").up().toString())
|
|
} else {
|
|
ws.send(XMLBuilder.create("stream:features").attribute("xmlns:stream", "http://etherx.jabber.org/streams")
|
|
.element("mechanisms").attribute("xmlns", "urn:ietf:params:xml:ns:xmpp-sasl")
|
|
.element("mechanism", "PLAIN").up().up()
|
|
.element("ver").attribute("xmlns", "urn:xmpp:features:rosterver").up()
|
|
.element("starttls").attribute("xmlns", "urn:ietf:params:xml:ns:xmpp-tls").up()
|
|
.element("compression").attribute("xmlns", "http://jabber.org/features/compress")
|
|
.element("method", "zlib").up().up()
|
|
.element("auth").attribute("xmlns", "http://jabber.org/features/iq-auth").up().toString())
|
|
}
|
|
break;
|
|
|
|
case "auth":
|
|
if (!msg.root.content) return Error(ws);
|
|
if (!functions.DecodeBase64(msg.root.content)) return Error(ws);
|
|
if (!functions.DecodeBase64(msg.root.content).includes("\u0000")) return Error(ws);
|
|
var decodedBase64 = functions.DecodeBase64(msg.root.content).split("\u0000");
|
|
|
|
if (global.Clients.find(i => i.accountId == decodedBase64[1])) return Error(ws);
|
|
|
|
accountId = decodedBase64[1];
|
|
|
|
if (decodedBase64 && accountId && decodedBase64.length == 3) {
|
|
Authenticated = true;
|
|
|
|
console.log(`An xmpp client with the account id ${accountId} has logged in.`);
|
|
|
|
ws.send(XMLBuilder.create("success").attribute("xmlns", "urn:ietf:params:xml:ns:xmpp-sasl").toString());
|
|
} else {
|
|
return Error(ws);
|
|
}
|
|
break;
|
|
|
|
case "iq":
|
|
switch (msg.root.attributes.id) {
|
|
case "_xmpp_bind1":
|
|
if (!msg.root.children.find(i => i.name == "bind")) return;
|
|
if (!msg.root.children.find(i => i.name == "bind").children.find(i => i.name == "resource")) return;
|
|
var resource = msg.root.children.find(i => i.name == "bind").children.find(i => i.name == "resource").content;
|
|
jid = `${accountId}@prod.ol.epicgames.com/${resource}`;
|
|
id = `${accountId}@prod.ol.epicgames.com`;
|
|
|
|
ws.send(XMLBuilder.create("iq")
|
|
.attribute("to", jid)
|
|
.attribute("id", "_xmpp_bind1")
|
|
.attribute("xmlns", "jabber:client")
|
|
.attribute("type", "result")
|
|
.element("bind")
|
|
.attribute("xmlns", "urn:ietf:params:xml:ns:xmpp-bind")
|
|
.element("jid", jid).up().up().toString())
|
|
break;
|
|
|
|
case "_xmpp_session1":
|
|
if (!global.Clients.find(i => i.client == ws)) return Error(ws);
|
|
var xml = XMLBuilder.create("iq")
|
|
.attribute("to", jid)
|
|
.attribute("from", "prod.ol.epicgames.com")
|
|
.attribute("id", "_xmpp_session1")
|
|
.attribute("xmlns", "jabber:client")
|
|
.attribute("type", "result");
|
|
|
|
ws.send(xml.toString());
|
|
getPresenceFromAll(ws);
|
|
break;
|
|
|
|
default:
|
|
if (!global.Clients.find(i => i.client == ws)) return Error(ws);
|
|
var xml = XMLBuilder.create("iq")
|
|
.attribute("to", jid)
|
|
.attribute("from", "prod.ol.epicgames.com")
|
|
.attribute("id", msg.root.attributes.id)
|
|
.attribute("xmlns", "jabber:client")
|
|
.attribute("type", "result");
|
|
|
|
ws.send(xml.toString());
|
|
}
|
|
break;
|
|
|
|
case "message":
|
|
if (!global.Clients.find(i => i.client == ws)) return Error(ws);
|
|
if (!msg.root.children.find(i => i.name == "body")) return;
|
|
var body = msg.root.children.find(i => i.name == "body").content;
|
|
|
|
if (msg.root.attributes.type) {
|
|
if (msg.root.attributes.type == "chat") {
|
|
if (!msg.root.attributes.to) return;
|
|
var receiver = global.Clients.find(i => i.id == msg.root.attributes.to);
|
|
var sender = global.Clients.find(i => i.client == ws);
|
|
if (!receiver || !sender) return;
|
|
if (receiver == sender) return;
|
|
|
|
receiver.client.send(XMLBuilder.create("message")
|
|
.attribute("to", receiver.jid)
|
|
.attribute("from", sender.jid)
|
|
.attribute("xmlns", "jabber:client")
|
|
.attribute("type", "chat")
|
|
.element("body", body).up().toString())
|
|
return;
|
|
}
|
|
}
|
|
|
|
if (ifJSON(body)) {
|
|
var object = JSON.parse(body);
|
|
|
|
if (object.hasOwnProperty("type")) {
|
|
if (typeof object.type == "string") {
|
|
switch (object.type.toLowerCase()) {
|
|
case "com.epicgames.party.invitation":
|
|
if (!msg.root.attributes.to) return;
|
|
var sender = global.Clients.find(i => i.client == ws);
|
|
var receiver = global.Clients.find(i => i.id == msg.root.attributes.to);
|
|
if (!receiver) return;
|
|
|
|
receiver.client.send(XMLBuilder.create("message")
|
|
.attribute("from", sender.jid)
|
|
.attribute("id", msg.root.attributes.id)
|
|
.attribute("to", receiver.jid)
|
|
.attribute("xmlns", "jabber:client")
|
|
.element("body", body).up().toString())
|
|
break;
|
|
|
|
default:
|
|
ws.send(XMLBuilder.create("message")
|
|
.attribute("from", jid)
|
|
.attribute("id", msg.root.attributes.id)
|
|
.attribute("to", jid)
|
|
.attribute("xmlns", "jabber:client")
|
|
.element("body", body).up().toString());
|
|
}
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
|
|
case "presence":
|
|
if (!global.Clients.find(i => i.client == ws)) return Error(ws);
|
|
if (!msg.root.children.find(i => i.name == "status")) return;
|
|
if (!ifJSON(msg.root.children.find(i => i.name == "status").content)) return;
|
|
var body = msg.root.children.find(i => i.name == "status").content;
|
|
var away = false;
|
|
if (msg.root.children.find(i => i.name == "show")) away = true;
|
|
|
|
updatePresenceForAll(ws, body, away, false)
|
|
break;
|
|
}
|
|
|
|
if (!global.Clients.find(i => i.client == ws)) {
|
|
if (accountId && jid && ID && id && Authenticated == true) {
|
|
global.Clients.push({ "client": ws, "accountId": accountId, "jid": jid, "id": id, "lastPresenceUpdate": { "away": false, "status": "{}" } });
|
|
}
|
|
}
|
|
})
|
|
|
|
ws.on('close', () => RemoveClient(ws))
|
|
})
|
|
|
|
function RemoveClient(ws) {
|
|
if (global.Clients.find(i => i.client == ws)) {
|
|
updatePresenceForAll(ws, "{}", false, true);
|
|
|
|
console.log(`An xmpp client with the account id ${global.Clients.find(i => i.client == ws).accountId} has logged out.`);
|
|
|
|
global.Clients.splice(global.Clients.findIndex(i => i.client == ws), 1);
|
|
}
|
|
}
|
|
|
|
function Error(ws) {
|
|
ws.send(XMLBuilder.create("close").attribute("xmlns", "urn:ietf:params:xml:ns:xmpp-framing").toString());
|
|
ws.close();
|
|
}
|
|
|
|
function updatePresenceForAll(ws, body, away, offline) {
|
|
if (global.Clients.find(i => i.client == ws)) {
|
|
var SenderData = global.Clients.find(i => i.client == ws);
|
|
var SenderIndex = global.Clients.findIndex(i => i.client == ws);
|
|
global.Clients[SenderIndex].lastPresenceUpdate.away = away;
|
|
global.Clients[SenderIndex].lastPresenceUpdate.status = body;
|
|
|
|
global.Clients.forEach(ClientData => {
|
|
var xml = XMLBuilder.create("presence")
|
|
.attribute("to", ClientData.jid)
|
|
.attribute("xmlns", "jabber:client")
|
|
.attribute("from", SenderData.jid)
|
|
|
|
if (offline == true) xml = xml.attribute("type", "unavailable");
|
|
else xml = xml.attribute("type", "available")
|
|
|
|
if (away == true) xml = xml.element("show", "away").up().element("status", body).up();
|
|
else xml = xml.element("status", body).up();
|
|
|
|
ClientData.client.send(xml.toString())
|
|
})
|
|
} else {
|
|
return Error(ws);
|
|
}
|
|
}
|
|
|
|
function getPresenceFromAll(ws) {
|
|
if (global.Clients.find(i => i.client == ws)) {
|
|
var SenderData = global.Clients.find(i => i.client == ws);
|
|
|
|
global.Clients.forEach(ClientData => {
|
|
var xml = XMLBuilder.create("presence")
|
|
.attribute("to", SenderData.jid)
|
|
.attribute("xmlns", "jabber:client")
|
|
.attribute("from", ClientData.jid)
|
|
|
|
if (ClientData.lastPresenceUpdate.away == true) xml = xml.attribute("type", "available").element("show", "away").up().element("status", ClientData.lastPresenceUpdate.status).up();
|
|
else xml = xml.attribute("type", "available").element("status", ClientData.lastPresenceUpdate.status).up();
|
|
|
|
SenderData.client.send(xml.toString())
|
|
})
|
|
} else {
|
|
return Error(ws);
|
|
}
|
|
}
|
|
|
|
function ifJSON(str) {
|
|
try {
|
|
JSON.parse(str)
|
|
} catch (err) {
|
|
return false;
|
|
}
|
|
return true;
|
|
} |