From 014b18caf87f57f13065f282e79b5df9300cbd39 Mon Sep 17 00:00:00 2001 From: Cooldude2606 <25043174+Cooldude2606@users.noreply.github.com> Date: Wed, 4 Mar 2026 21:02:39 +0000 Subject: [PATCH] Fix type of controller.auth_secret --- packages/controller/controller.ts | 5 +++-- packages/controller/src/Controller.ts | 10 +++++---- packages/controller/src/UserManager.ts | 3 ++- packages/controller/src/WsServer.ts | 28 +++++--------------------- packages/controller/src/routes.ts | 14 ++----------- packages/lib/src/config/classes.ts | 2 +- packages/lib/src/config/definitions.ts | 4 ++-- 7 files changed, 21 insertions(+), 45 deletions(-) diff --git a/packages/controller/controller.ts b/packages/controller/controller.ts index 16b2d343..95c6ec93 100644 --- a/packages/controller/controller.ts +++ b/packages/controller/controller.ts @@ -182,7 +182,8 @@ async function handleBootstrapCommand( // eslint-disable-next-line no-console console.log(jwt.sign( { aud: "host", host: args.id }, - Buffer.from(controllerConfig.get("controller.auth_secret"), "base64") + // Auth secret is never null after startup + Buffer.from(controllerConfig.get("controller.auth_secret")!, "base64") )); } else if (subCommand === "create-ctl-config") { @@ -387,7 +388,7 @@ async function initialize(): Promise { controllerConfig.set("controller.version", version); // Allows tracking last loaded version - if (controllerConfig.get("controller.auth_secret") === "") { + if (!controllerConfig.get("controller.auth_secret")) { logger.info("Generating new controller authentication secret"); let asyncRandomBytes = util.promisify(crypto.randomBytes); let bytes = await asyncRandomBytes(256); diff --git a/packages/controller/src/Controller.ts b/packages/controller/src/Controller.ts index 7ad03e2c..628073cc 100644 --- a/packages/controller/src/Controller.ts +++ b/packages/controller/src/Controller.ts @@ -261,6 +261,11 @@ export default class Controller { this.users.records.on("update", this.usersUpdated.bind(this)); } + get authSecret() { + // Auth secret is never null after startup + return Buffer.from(this.config.get("controller.auth_secret")!, "base64"); + } + async start(args: ControllerArgs) { if (this._state !== "new") { throw new Error(`Cannot start in state ${this._state}`); @@ -876,10 +881,7 @@ export default class Controller { * @param hostId - ID of host to generate a token for. */ generateHostToken(hostId: number): string { - return jwt.sign( - { aud: "host", host: hostId }, - Buffer.from(this.config.get("controller.auth_secret"), "base64") - ); + return jwt.sign({ aud: "host", host: hostId }, this.authSecret); } hostsUpdated(hosts: HostRecord[]) { diff --git a/packages/controller/src/UserManager.ts b/packages/controller/src/UserManager.ts index 2c727f30..d1304d14 100644 --- a/packages/controller/src/UserManager.ts +++ b/packages/controller/src/UserManager.ts @@ -151,7 +151,8 @@ export default class UserManager { signUserToken(user: UserRecord): string { return jwt.sign( { aud: "user", user: user.id }, - Buffer.from(this._controllerConfig.get("controller.auth_secret"), "base64") + // auth secret is never null after startup + Buffer.from(this._controllerConfig.get("controller.auth_secret")!, "base64") ); } diff --git a/packages/controller/src/WsServer.ts b/packages/controller/src/WsServer.ts index 819f8970..c2b33c81 100644 --- a/packages/controller/src/WsServer.ts +++ b/packages/controller/src/WsServer.ts @@ -223,10 +223,7 @@ ${err.stack}` createSession(dst: lib.Address): [ WsServerConnector, string ] { let sessionId = this.nextSessionId; this.nextSessionId += 1; - let sessionToken = jwt.sign( - { aud: this.sessionAud, sid: sessionId }, - Buffer.from(this.controller.config.get("controller.auth_secret"), "base64"), - ); + let sessionToken = jwt.sign({ aud: this.sessionAud, sid: sessionId }, this.controller.authSecret); let sessionTimeout = this.controller.config.get("controller.session_timeout"); let heartbeatInterval = this.controller.config.get("controller.heartbeat_interval"); let connector = new WsServerConnector(dst, sessionId, sessionTimeout, heartbeatInterval); @@ -247,13 +244,8 @@ ${err.stack}` } try { - let tokenPayload = jwt.verify( - data.token, - Buffer.from(this.controller.config.get("controller.auth_secret"), "base64"), - // migrate: allow pre-rename tokens issued to hosts before alpha-14 - { audience: ["host", "slave"] } - ); - + // migrate: allow pre-rename tokens issued to hosts before alpha-14 + const tokenPayload = jwt.verify(data.token, this.controller.authSecret, { audience: ["host", "slave"] }); if (typeof tokenPayload === "string") { throw new Error("unexpected JsonWebToken type"); } @@ -324,12 +316,7 @@ ${err.stack}` async registerControl(data: lib.RegisterControlData, socket: WebSocket, req: IncomingMessage) { let user; try { - let tokenPayload = jwt.verify( - data.token, - Buffer.from(this.controller.config.get("controller.auth_secret"), "base64"), - { audience: "user" } - ); - + const tokenPayload = jwt.verify(data.token, this.controller.authSecret, { audience: "user" }); if (typeof tokenPayload === "string") { throw new Error("unexpected JsonWebToken type"); } @@ -376,12 +363,7 @@ ${err.stack}` resumeSession(data: lib.ResumeData, socket: WebSocket, req: IncomingMessage) { let connector; try { - let payload = jwt.verify( - data.sessionToken, - Buffer.from(this.controller.config.get("controller.auth_secret"), "base64"), - { audience: this.sessionAud } - ); - + const payload = jwt.verify(data.sessionToken, this.controller.authSecret, { audience: this.sessionAud }); if (typeof payload === "string") { throw new Error("unexpected JsonWebToken type"); } diff --git a/packages/controller/src/routes.ts b/packages/controller/src/routes.ts index a47ceb2d..6b578dbd 100644 --- a/packages/controller/src/routes.ts +++ b/packages/controller/src/routes.ts @@ -148,12 +148,7 @@ function validateHostToken(req: Request, res: Response, next: any) { } try { - const tokenPayload = jwt.verify( - token, - Buffer.from(req.app.locals.controller.config.get("controller.auth_secret"), "base64"), - { audience: "host" } - ); - + const tokenPayload = jwt.verify(token, req.app.locals.controller.authSecret, { audience: "host" }); if (typeof tokenPayload === "string") { throw new Error("unexpected JsonWebToken type"); } @@ -180,12 +175,7 @@ function validateUserToken(req: Request, res: Response, next: any) { } try { - let tokenPayload = jwt.verify( - token, - Buffer.from(req.app.locals.controller.config.get("controller.auth_secret"), "base64"), - { audience: "user" } - ); - + const tokenPayload = jwt.verify(token, req.app.locals.controller.authSecret, { audience: "user" }); if (typeof tokenPayload === "string") { throw new Error("unexpected JsonWebToken type"); } diff --git a/packages/lib/src/config/classes.ts b/packages/lib/src/config/classes.ts index 2fc93982..0583342f 100644 --- a/packages/lib/src/config/classes.ts +++ b/packages/lib/src/config/classes.ts @@ -536,7 +536,7 @@ export class Config< this._checkAccess(name, def, this.location, ConfigAccess.write, true); } - // Empty strings are treat as null + // Empty strings are treated as null if (value === "") { value = null; } diff --git a/packages/lib/src/config/definitions.ts b/packages/lib/src/config/definitions.ts index dc4ca4d9..2461c76f 100644 --- a/packages/lib/src/config/definitions.ts +++ b/packages/lib/src/config/definitions.ts @@ -20,7 +20,7 @@ export interface ControllerConfigFields { "controller.public_url": string | null; "controller.tls_certificate": string | null; "controller.tls_private_key": string | null; - "controller.auth_secret": string; + "controller.auth_secret": string | null; "controller.heartbeat_interval": number; "controller.session_timeout": number; "controller.metrics_timeout": number; @@ -162,7 +162,7 @@ export class ControllerConfig extends classes.Config { "Do not share this.", restartRequired: true, type: "string", - initialValue: "", + optional: true, }, "controller.heartbeat_interval": { title: "Heartbeat Interval",