diff --git a/src/dashboard.ts b/src/dashboard.ts index 64cd5fc..db6f3e6 100644 --- a/src/dashboard.ts +++ b/src/dashboard.ts @@ -9,6 +9,43 @@ export function createDashboardRouter(config: Config): express.Router { router.use(express.json()); + // Authentication middleware + if (config.dashboard?.auth) { + router.use((req, res, next) => { + const auth = config.dashboard!.auth!; + + if (auth.type === 'basic') { + const authHeader = req.headers.authorization; + if (!authHeader || !authHeader.startsWith('Basic ')) { + res.setHeader('WWW-Authenticate', 'Basic realm="Troutbot Dashboard"'); + res.status(401).json({ error: 'Authentication required' }); + return; + } + + const credentials = Buffer.from(authHeader.slice(6), 'base64').toString('utf8'); + const [username, password] = credentials.split(':'); + + if (username !== auth.username || password !== auth.password) { + res.setHeader('WWW-Authenticate', 'Basic realm="Troutbot Dashboard"'); + res.status(401).json({ error: 'Invalid credentials' }); + return; + } + } else if (auth.type === 'token') { + const authHeader = req.headers.authorization; + const token = req.query.token as string | undefined; + + const providedToken = authHeader?.startsWith('Bearer ') ? authHeader.slice(7) : token; + + if (!providedToken || providedToken !== auth.token) { + res.status(401).json({ error: 'Invalid or missing token' }); + return; + } + } + + next(); + }); + } + // API routes router.get('/api/status', (_req, res) => { const enabledBackends = Object.entries(config.engine.backends) @@ -41,9 +78,9 @@ export function createDashboardRouter(config: Config): express.Router { try { const partial = req.body as Partial; const merged = deepMerge( - config as Record, - partial as Record - ) as Config; + config as unknown as Record, + partial as unknown as Record + ) as unknown as Config; validate(merged); // Apply in-place @@ -55,8 +92,7 @@ export function createDashboardRouter(config: Config): express.Router { } }); - // --- Dashboard HTML --- - + // Dashboard HTML router.get('/dashboard', (_req, res) => { res.type('html').send(dashboardHTML()); });