Files
KantSites/src/Ops/OriginCheck.php
T
kantarciandClaude Opus 5.5 b982cb8944 Give mail delivery its own admin page and move the origin probe off /.well-known
The mail page under System tries SMTP, PHP mail() and both sendmail
modes one by one or all at once, and saves the chosen way to .env
without ever showing the password. IONOS answers everything under
/.well-known/ itself with 403, so the address and HTTPS checks never
reached the installation; the probe now lives at /kantsites-origin
(ADR 122).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-12 21:07:27 +02:00

54 lines
2.1 KiB
PHP

<?php
namespace App\Ops;
/**
* Prüft, ob eine neue Adresse der Website wirklich bei dieser Installation ankommt.
*
* Die Adresse entscheidet, wohin die Schreibweise mit oder ohne www umgeleitet wird - für die
* Website und für die Verwaltung. Stellt jemand auf www um, und www hat keinen DNS-Eintrag oder
* kein Zertifikat, leitet danach jede Seite ins Leere, und in die Verwaltung kommt man nur noch
* über FTP. Deshalb wird vor dem Speichern angefragt: Unter der neuen Adresse muss eine Kennung
* zurückkommen, die nur diese Installation kennt - abgeleitet aus APP_SECRET, ohne es zu verraten.
*/
class OriginCheck
{
/**
* Bewusst nicht unter /.well-known/: IONOS beantwortet alles darunter selbst mit 403, bevor
* die Anfrage die Installation erreicht (huefner-gartenbau.de, 12.10.2026, ADR 122).
*/
public const PATH = '/kantsites-origin';
private Download $download;
public function __construct(private string $secret, ?Download $download = null)
{
// Kurz: die Anfrage geht an den eigenen Server und hält die Verwaltung so lange auf.
$this->download = $download ?? new Download(5, 10);
}
public function token(): string
{
return hash_hmac('sha256', 'site-origin', $this->secret);
}
/** Null, wenn die Adresse hier ankommt - sonst der Grund in einem Satz. */
public function problem(string $origin): ?string
{
if (!str_starts_with($origin, 'https://')) {
return 'Geprüft werden nur HTTPS-Adressen. Eine Adresse mit http:// lässt sich nur mit „Trotzdem übernehmen“ speichern.';
}
$antwort = $this->download->get($origin.self::PATH);
if (null === $antwort) {
$grund = $this->download->reason();
return 'Unter '.$origin.' antwortet diese Website nicht'.('' !== $grund ? ': '.rtrim($grund, '.').'.' : '.').' DNS-Eintrag und Zertifikat für diese Domain prüfen.';
}
if (!hash_equals($this->token(), trim($antwort))) {
return 'Unter '.$origin.' antwortet eine andere Website. Zeigt die Domain auf diesen Server?';
}
return null;
}
}