From 173ee8149f61ab026eb3e01095d9ac1c88f04e06 Mon Sep 17 00:00:00 2001 From: modeco80 Date: Sun, 26 May 2024 16:33:35 -0400 Subject: [PATCH] auth: Make more resilant to backend failures --- cvmts/src/AuthManager.ts | 10 ++++--- cvmts/src/WSServer.ts | 61 +++++++++++++++++++++++----------------- 2 files changed, 41 insertions(+), 30 deletions(-) diff --git a/cvmts/src/AuthManager.ts b/cvmts/src/AuthManager.ts index 4552264..081390b 100644 --- a/cvmts/src/AuthManager.ts +++ b/cvmts/src/AuthManager.ts @@ -25,12 +25,14 @@ export default class AuthManager { }) }); + // Make sure the fetch returned okay + if(!response.ok) + throw new Error(`Failed to query quth server: ${response.statusText}`) + let json = (await response.json()) as JoinResponse; - if (!json.success) { - this.logger.Error(`Failed to query auth server: ${json.error}`); - process.exit(1); - } + if (!json.success) + throw new Error(json.error); return json; } diff --git a/cvmts/src/WSServer.ts b/cvmts/src/WSServer.ts index 1194ac5..6e3164f 100644 --- a/cvmts/src/WSServer.ts +++ b/cvmts/src/WSServer.ts @@ -294,32 +294,38 @@ export default class WSServer { client.sendMsg(guacutils.encode('login', '0', 'You must connect to the VM before logging in.')); return; } - var res = await this.auth!.Authenticate(msgArr[1], client); - if (res.clientSuccess) { - this.logger.Info(`${client.IP.address} logged in as ${res.username}`); - client.sendMsg(guacutils.encode('login', '1')); - var old = this.clients.find((c) => c.username === res.username); - if (old) { - // kick() doesnt wait until the user is actually removed from the list and itd be anal to make it do that - // so we call connectionClosed manually here. When it gets called on kick(), it will return because the user isn't in the list - this.connectionClosed(old); - await old.kick(); - } - // Set username - this.renameUser(client, res.username); - // Set rank - client.rank = res.rank; - if (client.rank === Rank.Admin) { - client.sendMsg(guacutils.encode('admin', '0', '1')); - } else if (client.rank === Rank.Moderator) { - client.sendMsg(guacutils.encode('admin', '0', '3', this.ModPerms.toString())); - } - this.clients.forEach((c) => c.sendMsg(guacutils.encode('adduser', '1', client.username!, client.rank.toString()))); - } else { - client.sendMsg(guacutils.encode('login', '0', res.error!)); - if (res.error === 'You are banned') { - client.kick(); + try { + let res = await this.auth!.Authenticate(msgArr[1], client); + if (res.clientSuccess) { + this.logger.Info(`${client.IP.address} logged in as ${res.username}`); + client.sendMsg(guacutils.encode('login', '1')); + let old = this.clients.find((c) => c.username === res.username); + if (old) { + // kick() doesnt wait until the user is actually removed from the list and itd be anal to make it do that + // so we call connectionClosed manually here. When it gets called on kick(), it will return because the user isn't in the list + this.connectionClosed(old); + await old.kick(); + } + // Set username + this.renameUser(client, res.username); + // Set rank + client.rank = res.rank; + if (client.rank === Rank.Admin) { + client.sendMsg(guacutils.encode('admin', '0', '1')); + } else if (client.rank === Rank.Moderator) { + client.sendMsg(guacutils.encode('admin', '0', '3', this.ModPerms.toString())); + } + this.clients.forEach((c) => c.sendMsg(guacutils.encode('adduser', '1', client.username!, client.rank.toString()))); + } else { + client.sendMsg(guacutils.encode('login', '0', res.error!)); + if (res.error === 'You are banned') { + client.kick(); + } } + } catch(err) { + this.logger.Error(`Error authenticating client ${client.IP.address}: ${(err as Error).message}`); + // for now? + client.sendMsg(guacutils.encode('login', '0', 'There was an internal error while authenticating. Please let a staff member know as soon as possible')) } break; case 'list': @@ -915,7 +921,10 @@ export default class WSServer { async getThumbnail(): Promise { let display = this.VM.GetDisplay(); - if (!display.Connected()) throw new Error('VM display is not connected'); + + // oh well + if (!display.Connected()) + return ""; let buf = await JPEGEncoder.EncodeThumbnail(display.Buffer(), display.Size()); return buf.toString('base64');