dashboard: add authentication middleware

Signed-off-by: NotAShelf <raf@notashelf.dev>
Change-Id: I9910548c65a11f2c83dfeb4fef3c93f06a6a6964
This commit is contained in:
raf 2026-02-01 16:34:06 +03:00
commit 2db5fa502f
Signed by: NotAShelf
GPG key ID: 29D95B64378DB4BF

View file

@ -9,6 +9,43 @@ export function createDashboardRouter(config: Config): express.Router {
router.use(express.json()); 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 // API routes
router.get('/api/status', (_req, res) => { router.get('/api/status', (_req, res) => {
const enabledBackends = Object.entries(config.engine.backends) const enabledBackends = Object.entries(config.engine.backends)
@ -41,9 +78,9 @@ export function createDashboardRouter(config: Config): express.Router {
try { try {
const partial = req.body as Partial<Config>; const partial = req.body as Partial<Config>;
const merged = deepMerge( const merged = deepMerge(
config as Record<string, unknown>, config as unknown as Record<string, unknown>,
partial as Record<string, unknown> partial as unknown as Record<string, unknown>
) as Config; ) as unknown as Config;
validate(merged); validate(merged);
// Apply in-place // Apply in-place
@ -55,8 +92,7 @@ export function createDashboardRouter(config: Config): express.Router {
} }
}); });
// --- Dashboard HTML --- // Dashboard HTML
router.get('/dashboard', (_req, res) => { router.get('/dashboard', (_req, res) => {
res.type('html').send(dashboardHTML()); res.type('html').send(dashboardHTML());
}); });