Many changes. Commit before I break down.
- Authentication middleware uses Zod - PhotonRegionId in config - DB key changes and additions - WebSocket for SignalR mock - Presence additions * Needs modification for playerIds (do not store `Profile` in a set, this will cause sync issues) - Profile settings - Profile Device Class - Zod properly checks for issuer in token - Room scene type bug - Setting key import started - Instancing changes - PlayerReporting API route - Deduplicated auth/connect/token - match/player/login begin - WebSocket hands off connection to SignalR handler
This commit is contained in:
87
src/main.ts
87
src/main.ts
@@ -1,11 +1,19 @@
|
||||
import * as Log from "@proxnet/undead-logging";
|
||||
import * as Config from "./config.ts";
|
||||
import { Database } from "./db.ts";
|
||||
import { APIUtils } from "./apiutils.ts";
|
||||
import { APIUtils, ProfileTokenSchema } from "./apiutils.ts";
|
||||
import { Discord } from "./discord.ts";
|
||||
import { generateRandomString } from "./apiutils.ts";
|
||||
// @ts-types = "npm:@types/express"
|
||||
import express from "express";
|
||||
import WebSocket, { WebSocketServer } from "ws";
|
||||
import { IncomingMessage } from "../../AppData/Local/deno/npm/registry.npmjs.org/@types/connect/3.4.38/index.d.ts";
|
||||
import { decode } from "@gz/jwt";
|
||||
import Profile, { ProfileTokenFormat } from "./data/profiles.ts";
|
||||
import { SocketHandoff } from "./socket/handoff.ts";
|
||||
import internal from "node:stream";
|
||||
import { Buffer } from "node:buffer";
|
||||
import { SignalRSocketHandler } from "./socket/socket.ts";
|
||||
|
||||
const instanceId = generateRandomString(64);
|
||||
|
||||
@@ -20,15 +28,11 @@ if (typeof config == "undefined") {
|
||||
Deno.exit(1);
|
||||
}
|
||||
if (config.auth.secret == Config.defaultConfig.auth.secret) {
|
||||
log.e(
|
||||
`Cannot start: Auth secret is default. Please change 'secrets.authSecret' in 'config.json'`,
|
||||
);
|
||||
log.e(`Cannot start: Auth secret is default. Please change 'secrets.authSecret' in 'config.json'`);
|
||||
Deno.exit(1);
|
||||
}
|
||||
if (config.public.serverId == Config.defaultConfig.public.serverId) {
|
||||
log.e(
|
||||
`Cannot start: Server ID is default. Please change 'public.serverId' in 'config.json'`,
|
||||
);
|
||||
log.e(`Cannot start: Server ID is default. Please change 'public.serverId' in 'config.json'`);
|
||||
Deno.exit(1);
|
||||
}
|
||||
|
||||
@@ -77,6 +81,7 @@ const authRouter = await import("./routes/auth.ts");
|
||||
const accountRouter = await import("./routes/account.ts");
|
||||
const imgRouter = await import("./routes/img.ts");
|
||||
const matchRouter = await import("./routes/match.ts");
|
||||
const notifyRouter = await import("./socket/route.ts");
|
||||
|
||||
app.use(nameserverRouter.route.path, nameserverRouter.route.router);
|
||||
app.use(apiRouter.route.path, apiRouter.route.router);
|
||||
@@ -85,21 +90,16 @@ app.use(authRouter.route.path, authRouter.route.router);
|
||||
app.use(accountRouter.route.path, accountRouter.route.router);
|
||||
app.use(imgRouter.route.path, imgRouter.route.router);
|
||||
app.use(matchRouter.route.path, matchRouter.route.router);
|
||||
app.use(notifyRouter.route.path, notifyRouter.route.router);
|
||||
|
||||
app.use((rq: express.Request, rs: express.Response) => {
|
||||
log.e(
|
||||
`${APIUtils.getSrcIpDefault(rq)} 404 ${rq.method} ${rq.url.toString()}`,
|
||||
);
|
||||
log.e(`${APIUtils.getSrcIpDefault(rq)} 404 ${rq.method} ${rq.url.toString()}`);
|
||||
rs.statusCode = 404;
|
||||
rs.json(
|
||||
APIUtils.genericResponseFormat(
|
||||
true,
|
||||
"Endpoint not found. Check your syntax and/or method.",
|
||||
),
|
||||
);
|
||||
rs.json(APIUtils.genericResponseFormat(true, "Endpoint not found. Check your syntax and/or method."));
|
||||
});
|
||||
|
||||
try {
|
||||
|
||||
const http = app.listen(config.web.port, config.web.host, () => {
|
||||
log.n(`Listening on http://${config.web.host}:${config.web.port}`);
|
||||
|
||||
@@ -112,9 +112,62 @@ try {
|
||||
http.close();
|
||||
});
|
||||
});
|
||||
|
||||
const wss = new WebSocketServer({
|
||||
server: http,
|
||||
path: "/notify/hub/v1"
|
||||
});
|
||||
wss.on('connection', (ws: WebSocket, rq: IncomingMessage, profile: Profile, connectionId: string) => {
|
||||
const handoff = SocketHandoff.find(connectionId);
|
||||
if (handoff) handoff.complete();
|
||||
log.d(typeof profile);
|
||||
new SignalRSocketHandler(ws, profile);
|
||||
});
|
||||
http.on('upgrade', async (rq: IncomingMessage, socket: internal.Duplex, head: Buffer) => {
|
||||
const errorHandler = (err: Error | undefined) => { log.e(`Socket error: ${err?.stack}`); };
|
||||
socket.on('error', errorHandler);
|
||||
|
||||
function writeUnauthorized() {
|
||||
socket.write('HTTP/1.1 401 Unauthorized\r\n\r\n');
|
||||
socket.destroy();
|
||||
}
|
||||
|
||||
let wrong = false;
|
||||
const unparsedToken = rq.headers['Authorization'];
|
||||
const connectionId = new URL(`http://${rq.headers.host ? rq.headers.host : 'localhost'}${rq.url}`).searchParams.get('connectionId');
|
||||
if (connectionId == null) wrong = true;
|
||||
else {
|
||||
if (typeof unparsedToken == 'string') {
|
||||
const splitToken = unparsedToken.split(' ')[1]
|
||||
if (splitToken) {
|
||||
try {
|
||||
|
||||
const decodedToken = await decode<ProfileTokenFormat>(splitToken, config.auth.secret, {algorithm: 'HS512'});
|
||||
const schemaResult = ProfileTokenSchema.safeParse(decodedToken);
|
||||
if (!schemaResult.success) wrong = true;
|
||||
else {
|
||||
wss.handleUpgrade(rq, socket, head, (ws) => {
|
||||
wss.emit('connection', ws, rq, new Profile(decodedToken.sub), connectionId);
|
||||
});
|
||||
}
|
||||
|
||||
} catch {
|
||||
wrong = true;
|
||||
}
|
||||
} else wrong = true;
|
||||
} else wrong = true;
|
||||
}
|
||||
|
||||
if (wrong) {
|
||||
writeUnauthorized();
|
||||
return;
|
||||
}
|
||||
socket.removeListener('error', errorHandler);
|
||||
});
|
||||
|
||||
} catch (err) {
|
||||
log.e(`Cannot start: Network could not be initalized. ${err}`);
|
||||
Deno.exit(1);
|
||||
}
|
||||
|
||||
Discord.login();
|
||||
Discord.login();
|
||||
Reference in New Issue
Block a user