Add basic token generation, primitive memory profiling
This commit is contained in:
parent
4d11fc1049
commit
7138e02570
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
18
package.json
18
package.json
|
@ -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"
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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) {
|
||||
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 {
|
||||
// Generate a token
|
||||
generatedToken = await generateToken(socket.getUserID()) as string | undefined;
|
||||
generatedToken = await generateToken(socket.getUserID());
|
||||
if (!generatedToken) return;
|
||||
}
|
||||
} else {
|
||||
// TODO Ban the user for logging in without the browser
|
||||
// TODO config for this
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
]);
|
||||
|
||||
|
|
|
@ -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) => {
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in New Issue