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
|
## TODO
|
||||||
|
|
||||||
- Implement both UUID-based and JWT-based token auth
|
- 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
|
- Redo all of the validations with Zod
|
||||||
- This probably means making Zod schemas for every single message type
|
- This probably means making Zod schemas for every single message type
|
||||||
- Also user and channel data
|
- Also user and channel data
|
||||||
|
|
|
@ -23,8 +23,15 @@ adminParticipant:
|
||||||
|
|
||||||
# Allows admins to evaluate code through the "eval" message.
|
# Allows admins to evaluate code through the "eval" message.
|
||||||
# This is a security risk, so only enable this if you trust your admins.
|
# 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".
|
# 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".
|
# This server will still validate existing tokens generated with other schemes if not set to "none".
|
||||||
tokenAuth: 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": {
|
"dependencies": {
|
||||||
"@prisma/client": "5.7.0",
|
"@prisma/client": "5.7.0",
|
||||||
"@t3-oss/env-core": "^0.6.1",
|
"@t3-oss/env-core": "^0.6.1",
|
||||||
"bun-types": "^1.0.1",
|
"bun-types": "^1.1.20",
|
||||||
"commander": "^11.1.0",
|
"commander": "^11.1.0",
|
||||||
"date-holidays": "^3.21.5",
|
"date-holidays": "^3.23.12",
|
||||||
"events": "^3.3.0",
|
"events": "^3.3.0",
|
||||||
"fancy-text-converter": "^1.0.9",
|
"fancy-text-converter": "^1.0.9",
|
||||||
"jsonwebtoken": "^9.0.2",
|
"jsonwebtoken": "^9.0.2",
|
||||||
"keccak": "^2.1.0",
|
"keccak": "^2.1.0",
|
||||||
"nunjucks": "^3.2.4",
|
"nunjucks": "^3.2.4",
|
||||||
"unique-names-generator": "^4.7.1",
|
"unique-names-generator": "^4.7.1",
|
||||||
"yaml": "^2.3.2",
|
"yaml": "^2.4.5",
|
||||||
"zod": "^3.22.2"
|
"zod": "^3.23.8"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@types/bun": "latest",
|
"@types/bun": "latest",
|
||||||
"@types/jsonwebtoken": "^9.0.6",
|
"@types/jsonwebtoken": "^9.0.6",
|
||||||
"@types/node": "^20.5.9",
|
"@types/node": "^20.14.12",
|
||||||
"@types/nunjucks": "^3.2.6",
|
"@types/nunjucks": "^3.2.6",
|
||||||
"@typescript-eslint/eslint-plugin": "^6.19.1",
|
"@typescript-eslint/eslint-plugin": "^6.21.0",
|
||||||
"@typescript-eslint/parser": "^6.19.1",
|
"@typescript-eslint/parser": "^6.21.0",
|
||||||
"eslint": "^8.56.0",
|
"eslint": "^8.57.0",
|
||||||
"prisma": "5.7.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 { saveChatHistory, getChatHistory } from "../data/history";
|
||||||
import { mixin, darken } from "../util/helpers";
|
import { mixin, darken } from "../util/helpers";
|
||||||
import { User } from "@prisma/client";
|
import { User } from "@prisma/client";
|
||||||
|
import { heapStats } from "bun:jsc";
|
||||||
|
|
||||||
interface CachedKickban {
|
interface CachedKickban {
|
||||||
userId: string;
|
userId: string;
|
||||||
|
@ -112,6 +113,12 @@ export class Channel extends EventEmitter {
|
||||||
this.settings.owner_id = owner_id;
|
this.settings.owner_id = owner_id;
|
||||||
|
|
||||||
this.logger.info("Created");
|
this.logger.info("Created");
|
||||||
|
|
||||||
|
if (this.getID() == "test/mem") {
|
||||||
|
setInterval(() => {
|
||||||
|
this.printMemoryInChat();
|
||||||
|
}, 1000);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private alreadyBound = false;
|
private alreadyBound = false;
|
||||||
|
@ -205,8 +212,8 @@ export class Channel extends EventEmitter {
|
||||||
const ownsChannel = this.hasUser(socket.getUserID());
|
const ownsChannel = this.hasUser(socket.getUserID());
|
||||||
|
|
||||||
if (cmd == "help") {
|
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;
|
export default Channel;
|
||||||
|
|
|
@ -49,5 +49,17 @@ export function generateToken(id: string): Promise<string | undefined> | undefin
|
||||||
|
|
||||||
if (token) resolve(token);
|
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 { generateToken } from "../../../../util/token";
|
||||||
import { ServerEventListener } from "../../../../util/types";
|
import { ServerEventListener } from "../../../../util/types";
|
||||||
import { config } from "../../../usersConfig";
|
import { config } from "../../../usersConfig";
|
||||||
|
|
||||||
|
const logger = new Logger("Hi handler");
|
||||||
|
|
||||||
export const hi: ServerEventListener<"hi"> = {
|
export const hi: ServerEventListener<"hi"> = {
|
||||||
id: "hi",
|
id: "hi",
|
||||||
callback: async (msg, socket) => {
|
callback: async (msg, socket) => {
|
||||||
|
@ -9,21 +12,25 @@ export const hi: ServerEventListener<"hi"> = {
|
||||||
|
|
||||||
let generatedToken: string | undefined;
|
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 (config.tokenAuth !== "none") {
|
||||||
if (socket.gateway.hasCompletedBrowserChallenge) {
|
logger.debug("token auth is enabled");
|
||||||
if (msg.token) {
|
|
||||||
// Check if they have passed the browser challenge
|
// Is the browser challenge enabled and has the user completed it?
|
||||||
// Send the token to the authenticator
|
if (msg.token) {
|
||||||
// TODO
|
// Check if they have passed the browser challenge
|
||||||
} else {
|
// Send the token to the authenticator
|
||||||
// Generate a token
|
// TODO
|
||||||
generatedToken = await generateToken(socket.getUserID()) as string | undefined;
|
|
||||||
if (!generatedToken) return;
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
// TODO Ban the user for logging in without the browser
|
// Generate a token
|
||||||
// TODO config for this
|
generatedToken = await generateToken(socket.getUserID());
|
||||||
|
if (!generatedToken) return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
logger.debug("token:", generatedToken);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (socket.rateLimits)
|
if (socket.rateLimits)
|
||||||
|
@ -51,7 +58,8 @@ export const hi: ServerEventListener<"hi"> = {
|
||||||
_id: part._id,
|
_id: part._id,
|
||||||
color: part.color,
|
color: part.color,
|
||||||
name: part.name
|
name: part.name
|
||||||
}
|
},
|
||||||
|
token: generatedToken
|
||||||
}
|
}
|
||||||
]);
|
]);
|
||||||
|
|
||||||
|
|
|
@ -91,7 +91,7 @@ export const app = Bun.serve<{ ip: string }>({
|
||||||
// logger.debug("Connection at " + socket.getIP());
|
// logger.debug("Connection at " + socket.getIP());
|
||||||
|
|
||||||
// Let's put it in the dinner bucket.
|
// Let's put it in the dinner bucket.
|
||||||
socketsBySocketID.set(socket.socketID, socket);
|
socketsBySocketID.set((socket.socketID as any), socket);
|
||||||
},
|
},
|
||||||
|
|
||||||
message: (ws, message) => {
|
message: (ws, message) => {
|
||||||
|
|
|
@ -9,6 +9,7 @@ export interface UsersConfig {
|
||||||
adminParticipant: Participant;
|
adminParticipant: Participant;
|
||||||
enableAdminEval: boolean;
|
enableAdminEval: boolean;
|
||||||
tokenAuth: "jwt" | "uuid" | "none";
|
tokenAuth: "jwt" | "uuid" | "none";
|
||||||
|
browserChallenge: "none" | "obf" | "basic";
|
||||||
}
|
}
|
||||||
|
|
||||||
export const usersConfigPath = "config/users.yml";
|
export const usersConfigPath = "config/users.yml";
|
||||||
|
@ -27,7 +28,8 @@ export const defaultUsersConfig: UsersConfig = {
|
||||||
id: "0"
|
id: "0"
|
||||||
},
|
},
|
||||||
enableAdminEval: false,
|
enableAdminEval: false,
|
||||||
tokenAuth: "none"
|
tokenAuth: "none",
|
||||||
|
browserChallenge: "none"
|
||||||
};
|
};
|
||||||
|
|
||||||
// Importing this elsewhere causes bun to segfault
|
// Importing this elsewhere causes bun to segfault
|
||||||
|
|
Loading…
Reference in New Issue