fix(mam-api): narrow cluster carve-out to /cluster/heartbeat only
Code-review feedback: startsWith('/cluster') was a prefix match that exposed
destructive operator endpoints (POST /containers/:id/restart, DELETE /:id,
GET /devices/blackmagic/*) unauthenticated. Only POST /heartbeat is genuine
node-agent traffic; everything else in cluster.js is operator/UI surface
that should go through requireAuth. Long-term: issue node-agent a bound
api_token and drop the carve-out entirely.
This commit is contained in:
parent
9de4fe9ab9
commit
cb7cc9a43e
1 changed files with 9 additions and 4 deletions
|
|
@ -88,13 +88,18 @@ app.use(session({
|
||||||
app.get('/health', (_req, res) => res.json({ status: 'ok' }));
|
app.get('/health', (_req, res) => res.json({ status: 'ok' }));
|
||||||
|
|
||||||
// ── Auth gate ─────────────────────────────────────────────────────────────────
|
// ── Auth gate ─────────────────────────────────────────────────────────────────
|
||||||
// Mount once for everything under /api/v1, with an explicit allowlist for
|
// req.path is relative to the /api/v1 mount, so /auth/login NOT /api/v1/auth/login.
|
||||||
// the three pre-login auth paths and a carve-out for /cluster/* (node-agent
|
|
||||||
// uses migration 019's token-binding, not user auth). See spec.
|
|
||||||
const UNAUTH_PATHS = new Set(['/auth/login', '/auth/setup', '/auth/setup-required']);
|
const UNAUTH_PATHS = new Set(['/auth/login', '/auth/setup', '/auth/setup-required']);
|
||||||
|
// Service-auth carve-outs: node-agent uses migration 019's bound-hostname
|
||||||
|
// api_token mechanism, not user auth. Today only /cluster/heartbeat is
|
||||||
|
// reached without a user session — operator/UI endpoints in cluster.js
|
||||||
|
// (containers restart, DELETE /:id, blackmagic device queries) ARE expected
|
||||||
|
// to require auth. If node-agent grows another endpoint, add it here.
|
||||||
|
// TODO: long-term, issue node-agent a real bound api_token and drop this carve-out.
|
||||||
|
const SERVICE_PATHS = new Set(['/cluster/heartbeat']);
|
||||||
app.use('/api/v1', (req, res, next) => {
|
app.use('/api/v1', (req, res, next) => {
|
||||||
if (UNAUTH_PATHS.has(req.path)) return next();
|
if (UNAUTH_PATHS.has(req.path)) return next();
|
||||||
if (req.path.startsWith('/cluster')) return next(); // node-agent service auth, not user auth
|
if (SERVICE_PATHS.has(req.path)) return next();
|
||||||
return requireAuth(req, res, next);
|
return requireAuth(req, res, next);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue