86 lines
2.7 KiB
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];
|
|
}
|
|
}
|