Files
ita-ito-horaires/lib/device/transport.ts
T
vliaudatandClaude Opus 5 eae3f89aca fix: let the panel reach the API over plain HTTP, deliberately
The e-ink firmware carries a certificate-authority bundle fixed when it
was built, so it cannot validate a chain rooted in an authority created
afterwards. Let's Encrypt's ISRG Root YR was issued in May 2026 and is
not even in an up-to-date Ubuntu CA bundle yet; the kit's firmware
predates it. The handshake fails before a request is ever sent, which is
why neither Traefik nor the application saw anything at all while the
device reported "API connection cannot be established".

Ruled out first, with evidence: TLS 1.2 and the ECDHE-RSA-AES-GCM suites
an ESP32 needs are both offered, and the intermediate is not
cross-signed by an older root, so no alternate path exists in what is
served.

A Traefik router now serves four device paths over :80, ahead of the
entrypoint-wide redirect. The administration stays on TLS. The device
token travels in clear; it is used for nothing else and is revocable
from the settings page, and the image URL is an unguessable content hash.

DEVICE_ALLOW_HTTP existed but was never read — a setting that does
nothing misrepresents what it protects. The device routes now refuse an
unencrypted request unless it is set, so opening this door is a written
decision rather than the silent consequence of a proxy change.

DEPLOY.md records the whole diagnosis, including the commands that
distinguish a TLS failure from an application one, and what to do the
day the firmware learns the new roots.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012cSY9pVhZmJUKNN7wf1Myd
2026-09-21 22:17:16 +02:00

36 lines
1.3 KiB
TypeScript

/**
* Whether a device request arrived over a transport we accept.
*
* The panel's firmware carries a fixed certificate-authority bundle, so it
* cannot validate a chain rooted in an authority created after the firmware
* was built. When that happens the only way to reach the device is plain HTTP,
* and `DEVICE_ALLOW_HTTP` is the deliberate, auditable decision to allow it.
*
* Without that decision recorded, a proxy misconfiguration could silently
* start serving the device token in clear. This turns the setting from a
* comment into a rule.
*/
import { deviceAllowsHttp } from '@/lib/config';
export type TransportCheck = { ok: true } | { ok: false; response: Response };
export function checkTransport(request: Request): TransportCheck {
// Behind a reverse proxy the socket is always plain; the forwarded header is
// what says how the client actually connected.
const forwarded = request.headers.get('x-forwarded-proto');
const protocol = forwarded ?? new URL(request.url).protocol.replace(':', '');
if (protocol === 'https' || deviceAllowsHttp()) {
return { ok: true };
}
return {
ok: false,
response: Response.json(
{ error: 'HTTPS requis pour cet appareil.' },
{ status: 403, headers: { 'Cache-Control': 'no-store' } },
),
};
}