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
This commit is contained in:
@@ -3,6 +3,7 @@ import { NextResponse } from 'next/server';
|
||||
import { publicBaseUrl } from '@/lib/config';
|
||||
import { generateDeviceToken, generateFriendlyId, hashToken, normaliseMac } from '@/lib/device/auth';
|
||||
import { clientIp, deviceHeader } from '@/lib/device/headers';
|
||||
import { checkTransport } from '@/lib/device/transport';
|
||||
import { prisma } from '@/lib/db';
|
||||
import { rateLimit } from '@/lib/ratelimit';
|
||||
import { buildCurrentScreen, renderAndStore } from '@/lib/screen/service';
|
||||
@@ -19,6 +20,11 @@ export const dynamic = 'force-dynamic';
|
||||
* page — which is the correct outcome, not a gap.
|
||||
*/
|
||||
export async function GET(request: Request) {
|
||||
const transport = checkTransport(request);
|
||||
if (!transport.ok) {
|
||||
return transport.response;
|
||||
}
|
||||
|
||||
const limit = rateLimit(`setup:${clientIp(request)}`, 10, 60_000);
|
||||
if (!limit.allowed) {
|
||||
return NextResponse.json(
|
||||
|
||||
Reference in New Issue
Block a user