CluPilotCloud/app/Services/Proxy/CertificateSweep.php

86 lines
2.7 KiB
PHP

<?php
namespace App\Services\Proxy;
use App\Models\ProxyHost;
use App\Support\KnownHostnames;
/**
* Bringt die Liste auf den Stand der Installation und misst, was jeder Name
* gerade wirklich ausliefert.
*
* Zwei getrennte Hälften, mit Absicht: `sync()` kostet nichts und darf beim
* Öffnen der Seite laufen, `check()` geht ins Netz und läuft auf Knopfdruck
* oder nach Zeitplan. Beim Seitenaufruf zu messen hieße, den Betreiber auf ein
* halbes Dutzend TLS-Handschläge warten zu lassen — und einer davon ist immer
* der Name, der gerade nicht auflöst.
*/
class CertificateSweep
{
public function __construct(private CertificateInspector $inspector) {}
/**
* Die Namen aus der Umgebung in die Liste übernehmen.
*
* Anlegen und aktualisieren, nie löschen: ein Name, der aus der Umgebung
* verschwindet, bleibt als Zeile stehen. Sein Zertifikat läuft ja weiter,
* und ein Eintrag, der still verschwindet, ist genau das Gegenteil einer
* Übersicht.
*
* @return int wie viele Zeilen neu hinzugekommen sind
*/
public function sync(): int
{
$added = 0;
foreach (KnownHostnames::all() as $hostname => $purpose) {
$existing = ProxyHost::query()->where('hostname', $hostname)->first();
if ($existing === null) {
ProxyHost::create([
'hostname' => $hostname,
'purpose' => $purpose,
'source' => 'config',
]);
$added++;
continue;
}
// Ein von Hand angelegter Name, der inzwischen auch in der Umgebung
// steht, bleibt „manual" — sonst verlöre der Betreiber die
// Möglichkeit, ihn wieder zu entfernen, ohne je etwas dafür getan
// zu haben.
if ($existing->isFromConfig() && $existing->purpose !== $purpose) {
$existing->forceFill(['purpose' => $purpose])->save();
}
}
return $added;
}
/** @return array{checked: int, failing: int} */
public function check(): array
{
$checked = 0;
$failing = 0;
foreach (ProxyHost::query()->get() as $host) {
$result = $this->inspector->inspect($host->hostname);
$host->forceFill([
'certificate_expires_at' => $result['expires_at'],
'certificate_checked_at' => now(),
'certificate_error' => $result['error'],
])->save();
$checked++;
if ($result['error'] !== null) {
$failing++;
}
}
return ['checked' => $checked, 'failing' => $failing];
}
}