improve login system on the server

This commit is contained in:
hippoz 2022-02-15 14:24:46 +02:00
parent d24929da0c
commit ee2e192204
Signed by: hippoz
GPG key ID: 7C52899193467641
6 changed files with 86 additions and 25 deletions

View file

@ -2,11 +2,17 @@ import EventEmitter from "events";
import zlib from "zlib";
import { WebSocket } from "ws";
import fetch from "node-fetch";
import { logger } from "./common.js";
const log = logger("log", "DiscordClient");
const logError = logger("error", "DiscordClient");
const logWarn = logger("warn", "DiscordClient");
const opcodes = {
EVENT: 0,
CLIENT_HEARTBEAT: 1,
IDENTIFY: 2,
RECONNECT: 7,
INVALID_SESSION: 9,
HELLO: 10,
HEARTBEAT_ACK: 11,
@ -82,7 +88,7 @@ class DiscordClient extends EventEmitter {
try {
message = JSON.parse(message);
} catch(e) {
console.error("error: DiscordClient: on 'message': failed to parse incoming message as JSON", e);
logError("on 'message': failed to parse incoming message as JSON", e);
return;
}
@ -94,7 +100,7 @@ class DiscordClient extends EventEmitter {
switch (message.op) {
case opcodes.HELLO: {
console.log(`DiscordClient: HELLO; heartbeat_interval=${payload.heartbeat_interval}`);
log(`HELLO; heartbeat_interval=${payload.heartbeat_interval}`);
this._setHeartbeat(payload.heartbeat_interval);
ws.send(JSON.stringify({
@ -107,7 +113,7 @@ class DiscordClient extends EventEmitter {
case opcodes.EVENT: {
switch (message.t) {
case "READY": {
console.log("DiscordClient: READY");
log("READY");
this.user = payload.user;
this.sessionId = payload.session_id;
this.guilds = payload.guilds;
@ -194,22 +200,28 @@ class DiscordClient extends EventEmitter {
}
case opcodes.INVALID_SESSION: {
console.error("DiscordClient: INVALID_SESSION - please check your authentication token");
console.error("DiscordClient: INVALID_SESSION: will not reconnect");
logError("INVALID_SESSION - please check your authentication token");
logError("INVALID_SESSION: will not reconnect");
break;
}
case opcodes.RECONNECT: {
log("gateway is requesting reconnect (payload RECONNECT)");
this.connect();
break;
}
default: {
console.warn(`warn: DiscordClient: got unhandled opcode "${message.op}"`);
logWarn(`got unhandled opcode "${message.op}"`);
break;
}
}
}
connect() {
console.log("DiscordClient: connecting...");
log("connecting...");
if (this.ws) {
console.log("DiscordClient: a websocket connection already exists, killing...");
log("a websocket connection already exists, killing...");
this.ws.removeAllListeners();
this.ws.close();
this.ws = null;
@ -233,26 +245,26 @@ class DiscordClient extends EventEmitter {
ws.on("open", () => {
console.log("DiscordClient: WebSocket 'open'")
log("WebSocket 'open'");
});
ws.on("close", (code, reason) => {
reason = reason.toString();
console.error(`DiscordClient: on 'close': disconnected from gateway: code '${code}', reason '${reason}'`);
logError(`on 'close': disconnected from gateway: code '${code}', reason '${reason}'`);
this.emit("close", code, reason);
this._setHeartbeat(-1);
if (skipReconnectFor.includes(code)) {
console.error("DiscordClient: on 'close': the exit code above is in skipReconnectFor, and thus the server will not reconnect.");
logError("on 'close': the exit code above is in skipReconnectFor, and thus the server will not reconnect.");
} else {
console.log("DiscordClient: on 'close': the client will now attempt to reconnect...");
log("on 'close': the client will now attempt to reconnect...");
this.connect();
}
});
ws.on("error", (e) => {
console.error("DiscordClient: on 'error': websocket error:", e);
console.log("DiscordClient: on 'error': reconnecting due to previous websocket error...");
logError("on 'error': websocket error:", e);
log("on 'error': reconnecting due to previous websocket error...");
this._setHeartbeat(-1);
this.connect();
});

View file

@ -99,7 +99,6 @@ class GatewayServer {
try {
message = JSON.parse(message.toString());
} catch (e) {
console.error("GatewayServer: payload decode error", e);
return ws.close(4000, "Payload error.");
}
@ -113,7 +112,6 @@ class GatewayServer {
try {
user = await decodeToken(message.d.token);
} catch(e) {
console.error(e);
ws.close(4001, "Bad token.");
break;
}

View file

@ -1,4 +1,4 @@
import { discordToken, watchedGuildIds } from "./config.js";
import { discordToken, logContextMap, watchedGuildIds } from "./config.js";
import DiscordClient from "./DiscordClient.js";
import WatchedGuild from "./WatchedGuild.js";
@ -13,6 +13,36 @@ export function wait(time, shouldReject=false) {
});
}
export function logger(sink, context) {
let sinkFunction;
switch (sink) {
case "log": {
sinkFunction = console.log;
break;
}
case "warn": {
sinkFunction = console.warn;
break;
}
case "error": {
sinkFunction = console.error;
break;
}
default: {
sinkFunction = () => {};
break;
}
}
if (logContextMap[context] && logContextMap[context][sink]) {
return (...e) => {
sinkFunction(`[${context}]`, ...e);
};
} else {
return (...e) => {};
}
}
bot.once("READY", () => {
watchedGuildIds.forEach(id => {
const watchedGuild = new WatchedGuild();

View file

@ -3,3 +3,20 @@ export const watchedGuildIds = ["822089558886842418", "736292509134749807"];
export const jwtSecret = process.env.JWT_SECRET;
export const discordToken = process.env.DISCORD_TOKEN;
export const dangerousAdminMode = true;
export const logContextMap = {
DiscordClient: {
log: true,
warn: true,
error: true,
},
ServerMain: {
log: true,
warn: true,
error: true,
},
API: {
log: true,
warn: true,
error: true,
}
};

View file

@ -2,9 +2,11 @@ import http from "node:http";
import express from "express";
import apiRoute from "./routes/api.js";
import { mainHttpListenPort } from "./config.js";
import { bot } from "./common.js";
import { bot, logger } from "./common.js";
import GatewayServer from "./GatewayServer.js";
const log = logger("log", "ServerMain");
// might introduce bugs and probably a bad idea
Object.freeze(Object.prototype);
Object.freeze(Object);
@ -21,6 +23,6 @@ app.use("/", express.static("frontend/public/"));
app.use("/api/v1", apiRoute);
httpServer.listen(mainHttpListenPort, () => {
console.log(`server main: listen on ${mainHttpListenPort}`);
log(`http listen on ${mainHttpListenPort}`);
bot.connect();
});

View file

@ -1,8 +1,10 @@
import express from "express";
import { guildMap, wait } from "../common.js";
import { guildMap, logger } from "../common.js";
import { dangerousAdminMode } from "../config.js";
import { checkAuth, createToken } from "../tokens.js";
const error = logger("error", "API");
const router = express();
router.get("/", (req, res) => {
@ -69,7 +71,7 @@ router.post("/guilds/:guildId/channels/:channelId/messages/create", checkAuth(as
await guild.discordSendMessage(messageContent, channelId, username, avatarURL);
res.status(201).send({ error: false });
} catch(e) {
console.error("server main: api: message create: error: ", e);
error("[message create] [error]", e);
res.status(500).send({ error: true, message: "ERROR_MESSAGE_SEND_FAILURE" });
}
}));
@ -88,7 +90,7 @@ router.get("/guilds/:guildId/channels", checkAuth(async (req, res) => {
try {
res.status(200).send({ error: false, channels: guild.userFacingChannelList() });
} catch(e) {
console.error("server main: api: guild get channels: error: ", e);
error("[guild get channels] [error]", e);
res.status(500).send({ error: true, message: "ERROR_CHANNELS_FETCH_FAILURE" });
}
}));
@ -107,7 +109,7 @@ router.get("/guilds/:guildId", checkAuth(async (req, res) => {
try {
res.status(200).send({ error: false, guild: guild.guildObject });
} catch(e) {
console.error("server main: api: guild get info: error: ", e);
error("[guild get info]", e);
res.status(500).send({ error: true, message: "ERROR_GUILD_INFO_FETCH_FAILURE" });
}
}));
@ -133,7 +135,7 @@ router.get("/guilds/:guildId/events/poll", checkAuth(async (req, res) => {
guild.holdForEvent(15000)
.then(result => res.status(200).send({ error: false, event: result }));
} catch(e) {
console.error("server main: api: guild poll events: error: ", e);
error("[guild poll events]", e);
res.status(500).send({ error: true, message: "ERROR_POLL_FAILURE" });
}
}));
@ -157,7 +159,7 @@ router.get("/events/poll", checkAuth(async (req, res) => {
res.status(200).send({ error: false, event: e })
});
} catch(e) {
console.error("server main: api: guild poll events: error: ", e);
error("[guilds poll events]", e);
res.status(500).send({ error: true, message: "ERROR_POLL_FAILURE" });
}
}));