Add basic token generation, primitive memory profiling

This commit is contained in:
Hri7566 2024-07-26 19:38:24 -04:00
parent 4d11fc1049
commit 7138e02570
9 changed files with 70 additions and 28 deletions

View File

@ -46,6 +46,7 @@ Brandon's server originally used MongoDB for storing user data, but there are to
## TODO
- Implement both UUID-based and JWT-based token auth
- Add `openssl genrsa -out mppkey 2048` to the instructions
- Redo all of the validations with Zod
- This probably means making Zod schemas for every single message type
- Also user and channel data

BIN
bun.lockb

Binary file not shown.

View File

@ -23,8 +23,15 @@ adminParticipant:
# Allows admins to evaluate code through the "eval" message.
# This is a security risk, so only enable this if you trust your admins.
enableAdminEval: false
enableAdminEval: true
# The token validation scheme. Valid values are "none", "jwt" and "uuid".
# This server will still validate existing tokens generated with other schemes if not set to "none".
tokenAuth: none
# The browser challenge scheme. Valid values are "none", "obf" and "basic".
# This is to change what is sent in the "b" message.
# "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

View File

@ -9,27 +9,27 @@
"dependencies": {
"@prisma/client": "5.7.0",
"@t3-oss/env-core": "^0.6.1",
"bun-types": "^1.0.1",
"bun-types": "^1.1.20",
"commander": "^11.1.0",
"date-holidays": "^3.21.5",
"date-holidays": "^3.23.12",
"events": "^3.3.0",
"fancy-text-converter": "^1.0.9",
"jsonwebtoken": "^9.0.2",
"keccak": "^2.1.0",
"nunjucks": "^3.2.4",
"unique-names-generator": "^4.7.1",
"yaml": "^2.3.2",
"zod": "^3.22.2"
"yaml": "^2.4.5",
"zod": "^3.23.8"
},
"devDependencies": {
"@types/bun": "latest",
"@types/jsonwebtoken": "^9.0.6",
"@types/node": "^20.5.9",
"@types/node": "^20.14.12",
"@types/nunjucks": "^3.2.6",
"@typescript-eslint/eslint-plugin": "^6.19.1",
"@typescript-eslint/parser": "^6.19.1",
"eslint": "^8.56.0",
"@typescript-eslint/eslint-plugin": "^6.21.0",
"@typescript-eslint/parser": "^6.21.0",
"eslint": "^8.57.0",
"prisma": "5.7.0",
"typescript": "^5.2.2"
"typescript": "^5.5.4"
}
}

View File

@ -20,6 +20,7 @@ import { config as usersConfig } from "../ws/usersConfig";
import { saveChatHistory, getChatHistory } from "../data/history";
import { mixin, darken } from "../util/helpers";
import { User } from "@prisma/client";
import { heapStats } from "bun:jsc";
interface CachedKickban {
userId: string;
@ -112,6 +113,12 @@ export class Channel extends EventEmitter {
this.settings.owner_id = owner_id;
this.logger.info("Created");
if (this.getID() == "test/mem") {
setInterval(() => {
this.printMemoryInChat();
}, 1000);
}
}
private alreadyBound = false;
@ -205,8 +212,8 @@ export class Channel extends EventEmitter {
const ownsChannel = this.hasUser(socket.getUserID());
if (cmd == "help") {
} else if (cmd == "") {
} else if (cmd == "mem") {
this.printMemoryInChat();
}
});
@ -1139,6 +1146,11 @@ export class Channel extends EventEmitter {
}
}
}
public printMemoryInChat() {
const mem = heapStats();
this.sendChatAdmin(`Size: ${(mem.heapSize / 1000 / 1000).toFixed(2)}M / Capacity: ${(mem.heapCapacity / 1000 / 1000).toFixed(2)}M`);
}
}
export default Channel;

View File

@ -49,5 +49,17 @@ export function generateToken(id: string): Promise<string | undefined> | undefin
if (token) resolve(token);
});
} else return undefined;
} else return new Promise(() => undefined);
}
export function verifyToken(token: string) {
return jsonwebtoken.verify(token, privkey, { algorithms: ["RS256"] });
}
export async function decryptJWT(token: string) {
if (config.tokenAuth != "jwt") return undefined;
if (!privkey) throw new Error("Cannot decrypt JWT without private key loaded");
return jsonwebtoken.decode(token);
}

View File

@ -1,7 +1,10 @@
import { Logger } from "../../../../util/Logger";
import { generateToken } from "../../../../util/token";
import { ServerEventListener } from "../../../../util/types";
import { config } from "../../../usersConfig";
const logger = new Logger("Hi handler");
export const hi: ServerEventListener<"hi"> = {
id: "hi",
callback: async (msg, socket) => {
@ -9,21 +12,25 @@ export const hi: ServerEventListener<"hi"> = {
let generatedToken: string | undefined;
// Is the browser challenge enabled and has the user completed it?
if (config.browserChallenge !== "none" && !socket.gateway.hasCompletedBrowserChallenge) return;
// Is token auth enabled?
if (config.tokenAuth !== "none") {
if (socket.gateway.hasCompletedBrowserChallenge) {
if (msg.token) {
// Check if they have passed the browser challenge
// Send the token to the authenticator
// TODO
} else {
// Generate a token
generatedToken = await generateToken(socket.getUserID()) as string | undefined;
if (!generatedToken) return;
}
logger.debug("token auth is enabled");
// Is the browser challenge enabled and has the user completed it?
if (msg.token) {
// Check if they have passed the browser challenge
// Send the token to the authenticator
// TODO
} else {
// TODO Ban the user for logging in without the browser
// TODO config for this
// Generate a token
generatedToken = await generateToken(socket.getUserID());
if (!generatedToken) return;
}
logger.debug("token:", generatedToken);
}
if (socket.rateLimits)
@ -51,7 +58,8 @@ export const hi: ServerEventListener<"hi"> = {
_id: part._id,
color: part.color,
name: part.name
}
},
token: generatedToken
}
]);

View File

@ -91,7 +91,7 @@ export const app = Bun.serve<{ ip: string }>({
// logger.debug("Connection at " + socket.getIP());
// Let's put it in the dinner bucket.
socketsBySocketID.set(socket.socketID, socket);
socketsBySocketID.set((socket.socketID as any), socket);
},
message: (ws, message) => {

View File

@ -9,6 +9,7 @@ export interface UsersConfig {
adminParticipant: Participant;
enableAdminEval: boolean;
tokenAuth: "jwt" | "uuid" | "none";
browserChallenge: "none" | "obf" | "basic";
}
export const usersConfigPath = "config/users.yml";
@ -27,7 +28,8 @@ export const defaultUsersConfig: UsersConfig = {
id: "0"
},
enableAdminEval: false,
tokenAuth: "none"
tokenAuth: "none",
browserChallenge: "none"
};
// Importing this elsewhere causes bun to segfault