hvac: fetch MQTT credentials from Settings (drop .env secret)

getCredentials() now fetches the hvac-backend broker login from Settings'
new internal service-client endpoint (GET /internal/mqtt-client/hvac-backend,
bearer SETTINGS_SECRET) — same runtime-fetch pattern as newbook.js, no
broker secret in this app's .env. Env MQTT_* vars remain a dev-only override.
Drops the MQTT_USERNAME/PASSWORD compose passthrough added earlier.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
jtricerolph 2026-08-13 13:42:58 +00:00
parent c873e4a270
commit 6325532cfe
2 changed files with 11 additions and 14 deletions

View file

@ -82,12 +82,15 @@ let reconnectAttempt = 0
const discovered = new Map()
async function getCredentials() {
// Primary path: env-injected credentials for this app's own dynsec client.
// The installer provisions a `hvac-backend` broker client and writes its
// creds into /opt/hvac/.env. This is the working model because the broker
// stores each client's password show-once (Mosquitto dynsec hashes it), so
// it genuinely cannot be re-served from settings at runtime — settings only
// reveals a new client's password once, at creation.
// Fetch this app's broker login from the central Settings service at runtime —
// same pattern (and same SETTINGS_SECRET) as newbook.js's getCredentials().
// An admin creates a `hvac-backend` *service* MQTT client on the Settings
// "MQTT Broker Clients" page; Settings stores its password encrypted and serves
// it here. Nothing broker-related lives in this app's .env.
//
// Env override (dev/emergency only, not set in production compose): if explicit
// MQTT_* vars are present they win, so the app can run against a local broker
// without Settings.
if (process.env.MQTT_BROKER_HOST && process.env.MQTT_USERNAME && process.env.MQTT_PASSWORD) {
return {
host: process.env.MQTT_BROKER_HOST,
@ -96,14 +99,12 @@ async function getCredentials() {
password: process.env.MQTT_PASSWORD,
}
}
// Fallback: settings service (kept for the eventual self-service model — not
// wired yet; settings has no internal MQTT-credential serve endpoint today).
const url = `${process.env.SETTINGS_URL}/settings/api/internal/integration/mqtt?client=${CLIENT_NAME}`
const url = `${process.env.SETTINGS_URL}/settings/api/internal/mqtt-client/${CLIENT_NAME}`
const res = await fetch(url, {
headers: { Authorization: `Bearer ${process.env.SETTINGS_SECRET}` },
signal: AbortSignal.timeout(5000),
})
if (!res.ok) throw new Error(`Settings service returned ${res.status} fetching MQTT credentials`)
if (!res.ok) throw new Error(`Settings service returned ${res.status} fetching MQTT credentials (create a "${CLIENT_NAME}" service client in Settings)`)
const s = await res.json()
if (!s.host || !s.username || !s.password) throw new Error('MQTT broker credentials not configured in settings')
return { host: s.host, port: s.port || 1883, username: s.username, password: s.password }

View file

@ -8,10 +8,6 @@ services:
- CENTRAL_AUTH_SECRET=${CENTRAL_AUTH_SECRET}
- SETTINGS_URL=${SETTINGS_URL}
- SETTINGS_SECRET=${SETTINGS_SECRET}
- MQTT_BROKER_HOST=${MQTT_BROKER_HOST:-10.10.10.104}
- MQTT_BROKER_PORT=${MQTT_BROKER_PORT:-1883}
- MQTT_USERNAME=${MQTT_USERNAME:-}
- MQTT_PASSWORD=${MQTT_PASSWORD:-}
- APP_SLUG=hvac
- OFFICE_IP_CHECK=${OFFICE_IP_CHECK:-disabled}
- NEWBOOK_LOCATION_ID=${NEWBOOK_LOCATION_ID:-}