Eine Domain zu registrieren ist der kleinste Teil der Arbeit — DNS, Reverse Proxy und Zertifikat liegen ausserhalb dieser Anwendung. Fehlt dort etwas, merkt man es am gedruckten Code, der nicht aufgeht. Der Knopf "Pruefen" geht den Weg der Scanner nach: Namen aufloesen, Zertifikat ansehen, Adresse aufrufen — und sich beweisen lassen, dass am anderen Ende diese Installation steht. Der Beweis ist ein HMAC ueber eine frische Zufallszahl; das Geheimnis dafuer entsteht beim ersten Check und verlaesst den Server nie. Geprueft wird nur ein Hostname aus der Datenbank, nie einer aus der Anfrage — sonst waere die Route ein Werkzeug zum Abklopfen fremder Adressen. Scheitert schon DNS, fallen die drei Folgeschritte aus, statt dreimal dasselbe zu melden. Die Grenze der Aussage steht im Bericht selbst: Der Aufruf startet dort, wo der Container laeuft. Refs #7
41 lines
1.4 KiB
TypeScript
41 lines
1.4 KiB
TypeScript
import type { NextRequest } from "next/server";
|
|
|
|
import { bildeBeweis, getCheckSecret } from "@/lib/domain-check";
|
|
|
|
export const dynamic = "force-dynamic";
|
|
|
|
/**
|
|
* Beweis-Route für den Domain-Check.
|
|
*
|
|
* Bewusst **ohne Anmeldung**: Der Aufruf kommt von außen über die zu prüfende
|
|
* Domain und trägt keine Sitzung mit sich. Preisgegeben wird dabei nichts —
|
|
* die Antwort ist ein HMAC über die mitgeschickte Zufallszahl. Wer das
|
|
* Geheimnis nicht kennt, kann ihn nicht bilden; wer ihn sieht, lernt daraus
|
|
* nichts über das Geheimnis.
|
|
*
|
|
* Dass es diese Anwendung gibt, verrät ohnehin schon jede Landingpage.
|
|
*/
|
|
export async function GET(request: NextRequest): Promise<Response> {
|
|
const nonce = request.nextUrl.searchParams.get("nonce") ?? "";
|
|
|
|
// Eine Grenze nach oben, damit die Route nicht als Rechenknecht für fremde
|
|
// Daten taugt, und eine nach unten, damit sie nicht auf Zuruf antwortet.
|
|
if (!/^[a-f0-9]{16,64}$/.test(nonce)) {
|
|
return Response.json(
|
|
{ error: "Es fehlt eine gültige Zufallszahl." },
|
|
{ status: 400 },
|
|
);
|
|
}
|
|
|
|
try {
|
|
const proof = bildeBeweis(await getCheckSecret(), nonce);
|
|
return Response.json(
|
|
{ app: "qrcode-generator", proof },
|
|
{ headers: { "Cache-Control": "no-store" } },
|
|
);
|
|
} catch (error) {
|
|
console.error("Domain-Check konnte keinen Beweis bilden:", error);
|
|
return Response.json({ error: "Nicht möglich." }, { status: 500 });
|
|
}
|
|
}
|