fix super tokens and add minecraft server bridge
This commit is contained in:
parent
5ad5d0ceba
commit
2ab4277696
7 changed files with 184 additions and 4 deletions
|
@ -1,4 +1,3 @@
|
||||||
import { use } from "express/lib/application";
|
|
||||||
import { WebSocketServer } from "ws";
|
import { WebSocketServer } from "ws";
|
||||||
import { guildMap } from "./common.js";
|
import { guildMap } from "./common.js";
|
||||||
import { decodeToken } from "./tokens.js";
|
import { decodeToken } from "./tokens.js";
|
||||||
|
|
2
LICENSE
2
LICENSE
|
@ -1,6 +1,6 @@
|
||||||
MIT License
|
MIT License
|
||||||
|
|
||||||
Copyright (c) 2021 hippoz
|
Copyright (c) 2022 hippoz
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
export const mainHttpListenPort = 4050;
|
export const mainHttpListenPort = 4050;
|
||||||
export const watchedGuildIds = ["822089558886842418"];
|
export const watchedGuildIds = ["822089558886842418", "736292509134749807"];
|
||||||
export const jwtSecret = process.env.JWT_SECRET;
|
export const jwtSecret = process.env.JWT_SECRET;
|
||||||
export const discordToken = process.env.DISCORD_TOKEN;
|
export const discordToken = process.env.DISCORD_TOKEN;
|
||||||
export const dangerousAdminMode = true;
|
export const dangerousAdminMode = true;
|
||||||
|
|
|
@ -9,5 +9,8 @@
|
||||||
"jsonwebtoken": "^8.5.1",
|
"jsonwebtoken": "^8.5.1",
|
||||||
"node-fetch": "^3.2.0",
|
"node-fetch": "^3.2.0",
|
||||||
"ws": "^8.4.2"
|
"ws": "^8.4.2"
|
||||||
|
},
|
||||||
|
"optionalDependencies": {
|
||||||
|
"rcon": "^1.1.0"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -31,7 +31,7 @@ router.get("/users/@self", checkAuth(async (req, res) => {
|
||||||
avatarURL: req.user.avatarURL,
|
avatarURL: req.user.avatarURL,
|
||||||
discordID: req.user.discordID,
|
discordID: req.user.discordID,
|
||||||
guildAccess: req.user.guildAccess,
|
guildAccess: req.user.guildAccess,
|
||||||
isSuperToken: isSuperToken
|
isSuperToken: req.user.isSuperToken
|
||||||
}});
|
}});
|
||||||
}));
|
}));
|
||||||
|
|
||||||
|
@ -61,6 +61,10 @@ router.post("/guilds/:guildId/channels/:channelId/messages/create", checkAuth(as
|
||||||
return res.status(403).send({ error: true, message: "ERROR_NO_GUILD_ACCESS" });
|
return res.status(403).send({ error: true, message: "ERROR_NO_GUILD_ACCESS" });
|
||||||
|
|
||||||
const guild = guildMap.get(guildId);
|
const guild = guildMap.get(guildId);
|
||||||
|
|
||||||
|
if (!guild)
|
||||||
|
return res.status(404).send({ error: true, message: "ERROR_GUILD_NOT_FOUND" });
|
||||||
|
|
||||||
try {
|
try {
|
||||||
await guild.discordSendMessage(messageContent, channelId, username, avatarURL);
|
await guild.discordSendMessage(messageContent, channelId, username, avatarURL);
|
||||||
res.status(201).send({ error: false });
|
res.status(201).send({ error: false });
|
||||||
|
|
169
scripts/minecraft.js
Normal file
169
scripts/minecraft.js
Normal file
|
@ -0,0 +1,169 @@
|
||||||
|
// This script aims to bridge Minecraft to a guild of your choice by piping
|
||||||
|
// the Minecraft output into this script. RCON isrequired for messages to
|
||||||
|
// be sent to Minecraft.
|
||||||
|
|
||||||
|
import fetch from "node-fetch";
|
||||||
|
import { WebSocket } from "ws";
|
||||||
|
import Rcon from "rcon";
|
||||||
|
|
||||||
|
const TOKEN = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VybmFtZSI6InN0YWdpbmctbWluZWNyYWZ0LWJyaWRnZSIsImF2YXRhclVSTCI6bnVsbCwiZGlzY29yZElEIjoiMCIsImd1aWxkQWNjZXNzIjpbIjczNjI5MjUwOTEzNDc0OTgwNyJdLCJpc1N1cGVyVG9rZW4iOnRydWUsImlhdCI6MTY0NDQ1MzM4MX0.-XIBl6VLnXVwve9iqhWs51ABZkm1i_v1tS6X01SPk3U"; // A supertoken is required to send messages from Minecraft.
|
||||||
|
const TARGET_GUILD_ID = "_";
|
||||||
|
const TARGET_CHANNEL_ID = "_";
|
||||||
|
const ORIGIN = "http://localhost:4050";
|
||||||
|
const GATEWAY_ORIGIN = "ws://localhost:4050/gateway";
|
||||||
|
const messageSchema = { t: "number", d: "object" };
|
||||||
|
const messageTypes = {
|
||||||
|
HELLO: 0,
|
||||||
|
YOO: 1,
|
||||||
|
READY: 2,
|
||||||
|
EVENT: 3
|
||||||
|
};
|
||||||
|
|
||||||
|
const chatMessageRegex = /^\[(?:.*?)\]: \<(?<username>.*)\> (?<message>.*)/;
|
||||||
|
const rconConnection = new Rcon("localhost", "25575", process.env.RCON_PASSWORD);
|
||||||
|
|
||||||
|
export default class GatewayClient {
|
||||||
|
constructor(gatewayPath) {
|
||||||
|
this.gatewayPath = gatewayPath;
|
||||||
|
this.ws = null;
|
||||||
|
this.token = null;
|
||||||
|
this.user = null;
|
||||||
|
this.onEvent = (e) => {};
|
||||||
|
}
|
||||||
|
|
||||||
|
connect(token) {
|
||||||
|
if (!token)
|
||||||
|
token = this.token;
|
||||||
|
|
||||||
|
console.log("gateway: connecting");
|
||||||
|
|
||||||
|
this.ws = new WebSocket(this.gatewayPath);
|
||||||
|
|
||||||
|
this.ws.on("message", (data, isBinary) => {
|
||||||
|
if (isBinary) {
|
||||||
|
console.warn("gateway: got binary data from server, ignoring...");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
let message = data.toString();
|
||||||
|
try {
|
||||||
|
message = JSON.parse(data);
|
||||||
|
} catch(e) {
|
||||||
|
console.warn("gateway: got invalid JSON from server (failed to parse), ignoring...");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!this._checkMessageSchema(message)) {
|
||||||
|
console.warn("gateway: got invalid JSON from server (does not match schema), ignoring...");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (message.t) {
|
||||||
|
case messageTypes.HELLO: {
|
||||||
|
console.log("gateway: HELLO");
|
||||||
|
this.ws.send(JSON.stringify({
|
||||||
|
t: messageTypes.YOO,
|
||||||
|
d: {
|
||||||
|
token
|
||||||
|
}
|
||||||
|
}));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case messageTypes.READY: {
|
||||||
|
console.log("gateway: READY");
|
||||||
|
this.user = message.d.user;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case messageTypes.EVENT: {
|
||||||
|
this.onEvent(message.d);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default: {
|
||||||
|
console.warn("gateway: got invalid JSON from server (invalid type), ignoring...");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
this.ws.on("open", () => {
|
||||||
|
console.log("gateway: open");
|
||||||
|
});
|
||||||
|
this.ws.on("close", () => {
|
||||||
|
console.log("gateway: closed");
|
||||||
|
setTimeout(() => {
|
||||||
|
console.log("gateway: reconnecting");
|
||||||
|
this.connect(token);
|
||||||
|
}, 4000);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
_checkMessageSchema(message) {
|
||||||
|
for (const [key, value] of Object.entries(message)) {
|
||||||
|
if (!messageSchema[key])
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (typeof value !== messageSchema[key])
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
async function sendBridgeMessageAs(guildId, channelId, content, username=undefined, avatarURL=undefined) {
|
||||||
|
return await fetch(`${ORIGIN}/api/v1/guilds/${guildId}/channels/${channelId}/messages/create`, {
|
||||||
|
method: "POST",
|
||||||
|
body: JSON.stringify({
|
||||||
|
content,
|
||||||
|
username,
|
||||||
|
avatarURL
|
||||||
|
}),
|
||||||
|
headers: {
|
||||||
|
"content-type": "application/json",
|
||||||
|
"authorization": TOKEN
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
async function sendMinecraftMessageAs(rcon, username, content) {
|
||||||
|
rcon.send(`tellraw @a ${JSON.stringify([
|
||||||
|
{ text: "[" },
|
||||||
|
{ text: `${username}`, color: "gray" },
|
||||||
|
{ text: "]" },
|
||||||
|
{ text: " " },
|
||||||
|
{ text: content },
|
||||||
|
])}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
async function main() {
|
||||||
|
rconConnection.on("error", (e) => {
|
||||||
|
console.error("rcon: got error", e);
|
||||||
|
if (!rconConnection.hasAuthed) {
|
||||||
|
console.log("rcon: reconnecting in 1200ms due to error before hasAuthed");
|
||||||
|
setTimeout(() => {
|
||||||
|
rconConnection.connect();
|
||||||
|
}, 1200);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
const gateway = new GatewayClient(GATEWAY_ORIGIN);
|
||||||
|
gateway.onEvent = (e) => {
|
||||||
|
if (e.eventType === "MESSAGE_CREATE" && e.message.channel_id === TARGET_CHANNEL_ID && e.message.guild_id === TARGET_GUILD_ID && !e.message.webhook_id) {
|
||||||
|
sendMinecraftMessageAs(rconConnection, e.message.author.username, e.message.content);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
rconConnection.connect();
|
||||||
|
gateway.connect(TOKEN);
|
||||||
|
|
||||||
|
process.stdin.resume();
|
||||||
|
process.stdin.on("data", async (rawDataBuffer) => {
|
||||||
|
const stringData = rawDataBuffer.toString().trim();
|
||||||
|
console.log(stringData);
|
||||||
|
const result = chatMessageRegex.exec(stringData);
|
||||||
|
if (!result)
|
||||||
|
return;
|
||||||
|
const { username, message } = result.groups;
|
||||||
|
|
||||||
|
await sendBridgeMessageAs(TARGET_GUILD_ID, TARGET_CHANNEL_ID, message, username, null);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
await main();
|
|
@ -388,6 +388,11 @@ raw-body@2.4.2:
|
||||||
iconv-lite "0.4.24"
|
iconv-lite "0.4.24"
|
||||||
unpipe "1.0.0"
|
unpipe "1.0.0"
|
||||||
|
|
||||||
|
rcon@^1.1.0:
|
||||||
|
version "1.1.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/rcon/-/rcon-1.1.0.tgz#82a27bbfadd4c13b3c5d828b55ce15bd606eb7c3"
|
||||||
|
integrity sha512-eotwcApOBjfadTjqQlrZVR4jzlwGCMNxmHhnFZx+g4kouwwRstRHkk1ON7DzkqrHNIjADSh0cU3gThSsDolUpg==
|
||||||
|
|
||||||
safe-buffer@5.2.1, safe-buffer@^5.0.1:
|
safe-buffer@5.2.1, safe-buffer@^5.0.1:
|
||||||
version "5.2.1"
|
version "5.2.1"
|
||||||
resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.2.1.tgz#1eaf9fa9bdb1fdd4ec75f58f9cdb4e6b7827eec6"
|
resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.2.1.tgz#1eaf9fa9bdb1fdd4ec75f58f9cdb4e6b7827eec6"
|
||||||
|
|
Loading…
Reference in a new issue