From ec16301ae31c9d0c948a67b074df416f80a9150f Mon Sep 17 00:00:00 2001 From: Hri7566 Date: Sat, 27 Jul 2024 17:57:12 -0400 Subject: [PATCH] Basic token verification --- config/users.yml | 2 +- src/util/id.ts | 3 +- src/util/token.ts | 35 ++++++++++++++++++-- src/ws/Socket.ts | 9 ++++++ src/ws/events/user/handlers/b.ts | 8 ----- src/ws/events/user/handlers/hi.ts | 54 +++++++++++++++++++------------ 6 files changed, 77 insertions(+), 34 deletions(-) delete mode 100755 src/ws/events/user/handlers/b.ts diff --git a/config/users.yml b/config/users.yml index 31ec330..d1eeaca 100755 --- a/config/users.yml +++ b/config/users.yml @@ -34,4 +34,4 @@ tokenAuth: none # "none" will disable the browser challenge, # "obf" will sent an obfuscated function to the client, # and "basic" will just send a simple function that expects a boolean. -browserChallenge: none +browserChallenge: basic diff --git a/src/util/id.ts b/src/util/id.ts index cfda859..a5db5ab 100755 --- a/src/util/id.ts +++ b/src/util/id.ts @@ -1,5 +1,4 @@ -import { createHash, randomBytes } from "crypto"; -import env from "./env"; +import { createHash, randomBytes } from "crypto"; import env from "./env"; import { spoop_text } from "./helpers"; export function createID() { diff --git a/src/util/token.ts b/src/util/token.ts index bc93dcb..7f1853d 100644 --- a/src/util/token.ts +++ b/src/util/token.ts @@ -3,6 +3,7 @@ import jsonwebtoken from "jsonwebtoken"; import env from "./env"; import { readFileSync } from "fs"; import { Logger } from "./Logger"; +import { readUser, updateUser } from "../data/user"; let privkey: string; @@ -32,12 +33,24 @@ export function generateToken(id: string): Promise | undefin } else if (config.tokenAuth == "uuid") { logger.info("Generating UUID token for user " + id + "..."); - return new Promise((resolve, reject) => { + return new Promise(async (resolve, reject) => { let token: string | undefined; try { const uuid = crypto.randomUUID(); token = `${id}.${uuid}`; + + // Save token in user data + const user = await readUser(id); + if (!user) throw new Error("User not found"); + + if (!user.tokens) user.tokens = "[]"; + + const tokens = JSON.parse(user.tokens); + tokens.push(token); + + user.tokens = JSON.stringify(tokens); + await updateUser(user.id, user); } catch (err) { logger.warn("Token generation failed for user " + id); reject(err); @@ -52,8 +65,24 @@ export function generateToken(id: string): Promise | undefin } else return new Promise(() => undefined); } -export function verifyToken(token: string) { - return jsonwebtoken.verify(token, privkey, { algorithms: ["RS256"] }); +export async function verifyToken(token: string) { + if (config.tokenAuth !== "none") { + // Get tokens from user data + const user = await readUser(token.split(".")[0]); + if (!user) return false; + + if (!user.tokens) return false; + + const tokens = JSON.parse(user.tokens); + if (!tokens) return false; + + // Check if the token is in the list + for (const tok of tokens) { + if (tok === token) return true; + } + } + + return false; } export async function decryptJWT(token: string) { diff --git a/src/ws/Socket.ts b/src/ws/Socket.ts index 4d2ad41..a18f9b1 100755 --- a/src/ws/Socket.ts +++ b/src/ws/Socket.ts @@ -120,6 +120,15 @@ export class Socket extends EventEmitter { this.setNoteQuota(NoteQuota.PARAMS_RIDICULOUS); this.bindEventListeners(); + + if (config.browserChallenge == "basic") { + this.sendArray([{ + m: "b", + code: `~return true;` + }]); + } else if (config.browserChallenge == "obf") { + + } })(); } diff --git a/src/ws/events/user/handlers/b.ts b/src/ws/events/user/handlers/b.ts deleted file mode 100755 index 9af7d7c..0000000 --- a/src/ws/events/user/handlers/b.ts +++ /dev/null @@ -1,8 +0,0 @@ -import { ServerEventListener } from "../../../../util/types"; - -export const hi: ServerEventListener<"b"> = { - id: "b", - callback: (msg, socket) => { - // Antibot message - } -}; diff --git a/src/ws/events/user/handlers/hi.ts b/src/ws/events/user/handlers/hi.ts index e37db73..8587baf 100755 --- a/src/ws/events/user/handlers/hi.ts +++ b/src/ws/events/user/handlers/hi.ts @@ -1,6 +1,6 @@ import { Logger } from "../../../../util/Logger"; -import { generateToken } from "../../../../util/token"; -import { ServerEventListener } from "../../../../util/types"; +import { generateToken, verifyToken } from "../../../../util/token"; +import { ClientEvents, ServerEventListener } from "../../../../util/types"; import { config } from "../../../usersConfig"; const logger = new Logger("Hi handler"); @@ -9,9 +9,24 @@ export const hi: ServerEventListener<"hi"> = { id: "hi", callback: async (msg, socket) => { // Handshake message + if (socket.rateLimits) + if (!socket.rateLimits.normal.hi.attempt()) return; + + if (socket.gateway.hasProcessedHi) return; let generatedToken: string | undefined; + // Browser challenge + if (config.browserChallenge == "basic") { + if (typeof msg.code !== "boolean") return; + + if (msg.code === true) { + socket.gateway.hasCompletedBrowserChallenge = true; + } + } else if (config.browserChallenge == "obf") { + // TODO + } + // Is the browser challenge enabled and has the user completed it? if (config.browserChallenge !== "none" && !socket.gateway.hasCompletedBrowserChallenge) return; @@ -24,6 +39,7 @@ export const hi: ServerEventListener<"hi"> = { // Check if they have passed the browser challenge // Send the token to the authenticator // TODO + const verified = await verifyToken(msg.token); } else { // Generate a token generatedToken = await generateToken(socket.getUserID()); @@ -33,10 +49,6 @@ export const hi: ServerEventListener<"hi"> = { logger.debug("token:", generatedToken); } - if (socket.rateLimits) - if (!socket.rateLimits.normal.hi.attempt()) return; - - if (socket.gateway.hasProcessedHi) return; let part = socket.getParticipant(); if (!part) { @@ -48,20 +60,22 @@ export const hi: ServerEventListener<"hi"> = { }; } - socket.sendArray([ - { - m: "hi", - accountInfo: undefined, - permissions: undefined, - t: Date.now(), - u: { - _id: part._id, - color: part.color, - name: part.name - }, - token: generatedToken - } - ]); + const m = { + m: "hi", + accountInfo: undefined, + permissions: undefined, + t: Date.now(), + u: { + _id: part._id, + color: part.color, + name: part.name + }, + token: generatedToken + } + + logger.debug("Hi message:", m); + + socket.sendArray([m as ClientEvents["hi"]]); socket.gateway.hasProcessedHi = true; }