LawinServer XMPP 🔥

This commit is contained in:
Lawin0129
2022-02-28 19:39:25 +00:00
parent b36f83f0a6
commit 6c7002e788
13 changed files with 1087 additions and 328 deletions

View File

@@ -1,7 +1,10 @@
const Express = require("express");
const express = Express.Router();
const fs = require("fs");
const friendslist = require("./../responses/friendslist.json");
const friendslist2 = require("./../responses/friendslist2.json");
const functions = require("./functions.js");
const memory = require("./../memory.json");
express.get("/friends/api/v1/*/settings", async (req, res) => {
res.json({})
@@ -11,11 +14,99 @@ express.get("/friends/api/v1/*/blocklist", async (req, res) => {
res.json([])
})
express.get("/friends/api/public/friends/*", async (req, res) => {
express.get("/friends/api/public/friends/:accountId", async (req, res) => {
functions.GetVersionInfo(req, memory);
if (!friendslist.find(i => i.accountId == req.params.accountId)) {
var FriendObject = {
"accountId": req.params.accountId,
"status": "ACCEPTED",
"direction": "OUTBOUND",
"created": new Date().toISOString(),
"favorite": false
};
friendslist.push(FriendObject)
friendslist2.friends.push({
"accountId": FriendObject.accountId,
"groups": [],
"mutual": 0,
"alias": "",
"note": "",
"favorite": FriendObject.favorite,
"created": FriendObject.created
})
functions.sendXmppMessageToAll({
"payload": FriendObject,
"type": "com.epicgames.friends.core.apiobjects.Friend",
"timestamp": FriendObject.created
})
functions.sendXmppMessageToAll({
"type": "FRIENDSHIP_REQUEST",
"timestamp": FriendObject.created,
"from": FriendObject.accountId,
"status": FriendObject.status
})
fs.writeFileSync("./responses/friendslist.json", JSON.stringify(friendslist, null, 2));
fs.writeFileSync("./responses/friendslist2.json", JSON.stringify(friendslist2, null, 2));
}
if (memory.season >= 7) {
var friends = JSON.parse(JSON.stringify(friendslist))
friends.splice(friendslist.findIndex(i => i.accountId == req.params.accountId), 1)
return res.json(friends);
}
res.json(friendslist)
})
express.get("/friends/api/v1/*/summary", async (req, res) => {
express.get("/friends/api/v1/:accountId/summary", async (req, res) => {
if (!friendslist2.friends.find(i => i.accountId == req.params.accountId)) {
var FriendObject = {
"accountId": req.params.accountId,
"groups": [],
"mutual": 0,
"alias": "",
"note": "",
"favorite": false,
"created": new Date().toISOString()
};
friendslist2.friends.push(FriendObject)
friendslist.push({
"accountId": FriendObject.accountId,
"status": "ACCEPTED",
"direction": "OUTBOUND",
"created": FriendObject.created,
"favorite": FriendObject.favorite
})
functions.sendXmppMessageToAll({
"payload": {
"accountId": FriendObject.accountId,
"status": "ACCEPTED",
"direction": "OUTBOUND",
"created": FriendObject.created,
"favorite": FriendObject.favorite
},
"type": "com.epicgames.friends.core.apiobjects.Friend",
"timestamp": FriendObject.created
})
functions.sendXmppMessageToAll({
"type": "FRIENDSHIP_REQUEST",
"timestamp": FriendObject.created,
"from": FriendObject.accountId,
"status": "ACCEPTED"
})
fs.writeFileSync("./responses/friendslist.json", JSON.stringify(friendslist, null, 2));
fs.writeFileSync("./responses/friendslist2.json", JSON.stringify(friendslist2, null, 2));
}
res.json(friendslist2)
})

View File

@@ -1,5 +1,6 @@
const crypto = require("crypto");
const memory = require("./../memory.json");
const XMLBuilder = require("xmlbuilder");
function GetVersionInfo(req, memory) {
if (req.headers["user-agent"])
@@ -234,10 +235,30 @@ function MakeID() {
return FinishedID;
}
function sendXmppMessageToAll(body) {
if (global.Clients) {
if (typeof body == "object") body = JSON.stringify(body);
global.Clients.forEach(ClientData => {
ClientData.client.send(XMLBuilder.create("message")
.attribute("from", "xmpp-admin@prod.ol.epicgames.com")
.attribute("xmlns", "jabber:client")
.attribute("to", ClientData.jid)
.element("body", `${body}`).up().toString());
});
}
}
function DecodeBase64(str) {
return Buffer.from(str, 'base64').toString()
}
module.exports = {
GetVersionInfo,
getItemShop,
getTheater,
getContentPages,
MakeID
MakeID,
sendXmppMessageToAll,
DecodeBase64
}

View File

@@ -5,240 +5,65 @@ const path = require("path");
const iniparser = require("ini");
const config = iniparser.parse(fs.readFileSync(path.join(__dirname, "..", "Config", "config.ini")).toString());
const functions = require("./functions.js");
const accounts = require("./../responses/account.json");
var Memory_CurrentAccountID = functions.MakeID().replace(/-/ig, "");
express.get("/account/api/public/account", async (req, res) => {
var displayName = config.Config.displayName;
var response = [];
if (displayName.includes("@")) displayName = displayName.split("@")[0];
if (config.Config.bUseConfigDisplayName == false) {
displayName = req.query.accountId;
}
if (typeof req.query.accountId == "string") {
displayName = req.query.accountId;
if (displayName.includes("@")) displayName = displayName.split("@")[0];
res.json(
[
{
if (!accounts.find(i => i.id.toLowerCase() == req.query.accountId.toLowerCase())) {
accounts.push({
"id": req.query.accountId,
"displayName": displayName,
"externalAuths": {}
})
}
if (accounts.find(i => i.id.toLowerCase() == req.query.accountId.toLowerCase()).displayName != displayName) {
var index = accounts.findIndex(i => i.id.toLowerCase() == req.query.accountId.toLowerCase());
accounts[index].displayName = displayName;
}
}
} else if (typeof req.query.accountId == "string") {
if (!accounts.find(i => i.id.toLowerCase() == req.query.accountId.toLowerCase())) {
accounts.push({
"id": req.query.accountId,
"displayName": displayName,
"externalAuths": {}
},
{
"id": "SubtoLawin_LOL123",
"displayName": "Subscribe to Lawin on YouTube!",
"externalAuths": {
"xbl": {
"type": "xbl",
"externalAuthIdType": "xuid",
"accountId": "SubtoLawin_LOL123",
"externalDisplayName": "YouTube-Lawin",
"authIds": [{
"id": "0",
"type": "xuid"
}]
},
"psn": {
"type": "psn",
"externalAuthId": "0",
"externalAuthIdType": "psn_user_id",
"accountId": "SubtoLawin_LOL123",
"externalDisplayName": "YouTube-Lawin",
"authIds": [{
"id": "0",
"type": "psn_user_id"
}]
}
}
},
{
"id": "Followlawin_LOL123",
"displayName": "Follow @lawin_010 on twitter!",
"externalAuths": {
"xbl": {
"type": "xbl",
"externalAuthIdType": "xuid",
"accountId": "Followlawin_LOL123",
"externalDisplayName": "Twitter-lawin_010",
"authIds": [{
"id": "0",
"type": "xuid"
}]
},
"psn": {
"type": "psn",
"externalAuthId": "0",
"externalAuthIdType": "psn_user_id",
"accountId": "Followlawin_LOL123",
"externalDisplayName": "Twitter-lawin_010",
"authIds": [{
"id": "0",
"type": "psn_user_id"
}]
}
}
},
{
"id": "NINJALOL_1238",
"displayName": "Ninja",
"externalAuths": {
"xbl": {
"type": "xbl",
"externalAuthIdType": "xuid",
"accountId": "NINJALOL_1238",
"externalDisplayName": "Ninja",
"authIds": [{
"id": "0",
"type": "xuid"
}]
},
"psn": {
"type": "psn",
"externalAuthId": "0",
"externalAuthIdType": "psn_user_id",
"accountId": "NINJALOL_1238",
"externalDisplayName": "Ninja",
"authIds": [{
"id": "0",
"type": "psn_user_id"
}]
}
}
},
{
"id": "TFUELOL_1238",
"displayName": "Tfue",
"externalAuths": {
"xbl": {
"type": "xbl",
"externalAuthIdType": "xuid",
"accountId": "TFUELOL_1238",
"externalDisplayName": "Tfue",
"authIds": [{
"id": "0",
"type": "xuid"
}]
},
"psn": {
"type": "psn",
"externalAuthId": "0",
"externalAuthIdType": "psn_user_id",
"accountId": "TFUELOL_1238",
"externalDisplayName": "Tfue",
"authIds": [{
"id": "0",
"type": "psn_user_id"
}]
}
}
},
{
"id": "ALIALOL_1238",
"displayName": "Ali-A",
"externalAuths": {
"xbl": {
"type": "xbl",
"externalAuthIdType": "xuid",
"accountId": "ALIALOL_1238",
"externalDisplayName": "Ali-A",
"authIds": [{
"id": "0",
"type": "xuid"
}]
},
"psn": {
"type": "psn",
"externalAuthId": "0",
"externalAuthIdType": "psn_user_id",
"accountId": "ALIALOL_1238",
"externalDisplayName": "Ali-A",
"authIds": [{
"id": "0",
"type": "psn_user_id"
}]
}
}
},
{
"id": "DAKOTAZLOL_1238",
"displayName": "Dark",
"externalAuths": {
"xbl": {
"type": "xbl",
"externalAuthIdType": "xuid",
"accountId": "DAKOTAZLOL_1238",
"externalDisplayName": "Dark",
"authIds": [{
"id": "0",
"type": "xuid"
}]
},
"psn": {
"type": "psn",
"externalAuthId": "0",
"externalAuthIdType": "psn_user_id",
"accountId": "DAKOTAZLOL_1238",
"externalDisplayName": "Dark",
"authIds": [{
"id": "0",
"type": "psn_user_id"
}]
}
}
},
{
"id": "SYPHERPKLOL_1238",
"displayName": "SypherPK",
"externalAuths": {
"xbl": {
"type": "xbl",
"externalAuthIdType": "xuid",
"accountId": "SYPHERPKLOL_1238",
"externalDisplayName": "SypherPK",
"authIds": [{
"id": "0",
"type": "xuid"
}]
},
"psn": {
"type": "psn",
"externalAuthId": "0",
"externalAuthIdType": "psn_user_id",
"accountId": "SYPHERPKLOL_1238",
"externalDisplayName": "SypherPK",
"authIds": [{
"id": "0",
"type": "psn_user_id"
}]
}
}
},
{
"id": "NICKEH30LOLL_2897669",
"displayName": "Nick Eh 30",
"externalAuths": {
"xbl": {
"type": "xbl",
"externalAuthIdType": "xuid",
"accountId": "NICKEH30LOLL_2897669",
"externalDisplayName": "Nick Eh 30",
"authIds": [{
"id": "0",
"type": "xuid"
}]
},
"psn": {
"type": "psn",
"externalAuthId": "0",
"externalAuthIdType": "psn_user_id",
"accountId": "NICKEH30LOLL_2897669",
"externalDisplayName": "Nick Eh 30",
"authIds": [{
"id": "0",
"type": "psn_user_id"
}]
}
}
})
}
if (accounts.find(i => i.id.toLowerCase() == req.query.accountId.toLowerCase()).displayName != displayName) {
var index = accounts.findIndex(i => i.id.toLowerCase() == req.query.accountId.toLowerCase());
accounts[index].displayName = displayName;
}
}
if (typeof req.query.accountId == "string") {
if (accounts.find(i => i.id.toLowerCase() == req.query.accountId.toLowerCase())) {
response.push(accounts.find(i => i.id.toLowerCase() == req.query.accountId.toLowerCase()))
}
}
if (Array.isArray(req.query.accountId)) {
for (var x in req.query.accountId) {
if (accounts.find(i => i.id.toLowerCase() == req.query.accountId[x].toLowerCase())) {
response.push(accounts.find(i => i.id.toLowerCase() == req.query.accountId[x].toLowerCase()))
}
]
)
}
}
fs.writeFileSync("./responses/account.json", JSON.stringify(accounts, null, 2));
res.json(response)
})
express.get("/account/api/public/account/:accountId", async (req, res) => {
@@ -248,6 +73,8 @@ express.get("/account/api/public/account/:accountId", async (req, res) => {
displayName = req.params.accountId;
}
if (displayName.includes("@")) displayName = displayName.split("@")[0];
res.json({
"id": req.params.accountId,
"displayName": displayName,
@@ -315,8 +142,12 @@ express.post("/account/api/oauth/token", async (req, res) => {
if (config.Config.bUseConfigDisplayName == false) {
Memory_CurrentAccountID = req.body.username || "LawinServer"
displayName = req.body.username || "LawinServer"
if (Memory_CurrentAccountID.includes("@")) Memory_CurrentAccountID = Memory_CurrentAccountID.split("@")[0];
}
if (displayName.includes("@")) displayName = displayName.split("@")[0];
res.json({
"access_token": "lawinstokenlol",
"expires_in": 28800,

267
structure/xmpp.js Normal file
View File

@@ -0,0 +1,267 @@
const WebSocket = require("ws").Server;
const XMLBuilder = require("xmlbuilder");
const XMLParser = require("xml-parser");
const functions = require("./../structure/functions.js");
const port = 80;
const wss = new WebSocket({ port: port }, console.log("XMPP started listening on port", port));
global.Clients = [];
wss.on('connection', async (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.`);
Success(ws);
} 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 Success(ws) {
ws.send(XMLBuilder.create("success").attribute("xmlns", "urn:ietf:params:xml:ns:xmpp-sasl").toString());
}
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;
}