diff --git a/docker-compose.yml b/docker-compose.yml index 806c5ade..0d4059f3 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -245,6 +245,7 @@ services: - MAILCOW_API_URL=${MAILCOW_API_URL:-http://nginx-mailcow:8080} - MAILCOW_API_KEY=${MAILCOW_API_KEY:-} - ADMIN_DIDS=${ADMIN_DIDS} + - INTERNAL_API_KEY=${INTERNAL_API_KEY} labels: - "traefik.enable=true" - "traefik.http.routers.encryptid.rule=Host(`auth.rspace.online`) || Host(`auth.ridentity.online`) || Host(`encryptid.jeffemmett.com`)" diff --git a/src/encryptid/server.ts b/src/encryptid/server.ts index 0887e5b8..6da79f68 100644 --- a/src/encryptid/server.ts +++ b/src/encryptid/server.ts @@ -480,10 +480,25 @@ app.use('*', cors({ return undefined; }, allowMethods: ['GET', 'POST', 'PUT', 'DELETE', 'OPTIONS'], - allowHeaders: ['Content-Type', 'Authorization'], + allowHeaders: ['Content-Type', 'Authorization', 'X-Internal-Key'], credentials: true, })); +// /api/internal/* is for service-to-service calls over the Docker network only. +// Traefik adds X-Forwarded-For for any request arriving through the public edge +// (CF tunnel, direct HTTPS). Direct container-to-container fetches do not set it. +// A shared INTERNAL_API_KEY also works for callers outside the Docker net. +app.use('/api/internal/*', async (c, next) => { + const forwarded = c.req.header('X-Forwarded-For') || c.req.header('X-Real-IP'); + const providedKey = c.req.header('X-Internal-Key'); + const expectedKey = process.env.INTERNAL_API_KEY; + const hasValidKey = !!(expectedKey && providedKey && providedKey === expectedKey); + if (forwarded && !hasValidKey) { + return c.json({ error: 'Not found' }, 404); + } + return next(); +}); + // ============================================================================ // STATIC FILES & WELL-KNOWN // ============================================================================