Compare commits
No commits in common. "d3f2533565c1fbc372e1d7018a5661e133d8c902" and "d013124c12012846e464d9d319cec3306fa22e0f" have entirely different histories.
d3f2533565
...
d013124c12
|
|
@ -22,17 +22,18 @@ class CertificateSweep
|
|||
/**
|
||||
* 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
|
||||
{
|
||||
$bekannt = KnownHostnames::all();
|
||||
|
||||
$this->pruneVanished($bekannt);
|
||||
|
||||
$added = 0;
|
||||
|
||||
foreach ($bekannt as $hostname => $purpose) {
|
||||
foreach (KnownHostnames::all() as $hostname => $purpose) {
|
||||
$existing = ProxyHost::query()->where('hostname', $hostname)->first();
|
||||
|
||||
if ($existing === null) {
|
||||
|
|
@ -58,41 +59,6 @@ class CertificateSweep
|
|||
return $added;
|
||||
}
|
||||
|
||||
/**
|
||||
* Zeilen, die aus der Umgebung kamen und dort nicht mehr stehen.
|
||||
*
|
||||
* Zwei Fälle, und sie brauchen zwei Antworten:
|
||||
*
|
||||
* - Die Zeile hatte NIE ein Zertifikat. Dann war sie ein Fehlgriff — so
|
||||
* kam `127.0.0.1` aus `ADMIN_HOSTS` in die Liste, wo eine nackte IP als
|
||||
* Wiederzugang stehen darf, für die es aber nie ein Zertifikat geben
|
||||
* wird. Sie geht weg; ein dauerhaft roter Eintrag, den niemand beheben
|
||||
* kann, macht die Übersicht unlesbar.
|
||||
* - Die Zeile HAT ein Zertifikat. Dann wird sie zu einem Eintrag von Hand,
|
||||
* statt zu verschwinden. Das Zertifikat läuft ja weiter, und etwas mit
|
||||
* einer laufenden Frist still aus einer Übersicht zu nehmen ist das
|
||||
* Gegenteil einer Übersicht — der Betreiber entfernt sie selbst.
|
||||
*
|
||||
* @param array<string, string> $bekannt
|
||||
*/
|
||||
private function pruneVanished(array $bekannt): void
|
||||
{
|
||||
$verschwunden = ProxyHost::query()
|
||||
->where('source', 'config')
|
||||
->whereNotIn('hostname', array_keys($bekannt))
|
||||
->get();
|
||||
|
||||
foreach ($verschwunden as $host) {
|
||||
if ($host->hasCertificate()) {
|
||||
$host->forceFill(['source' => 'manual'])->save();
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
$host->delete();
|
||||
}
|
||||
}
|
||||
|
||||
/** @return array{checked: int, failing: int} */
|
||||
public function check(): array
|
||||
{
|
||||
|
|
|
|||
|
|
@ -59,27 +59,6 @@ final class KnownHostnames
|
|||
return;
|
||||
}
|
||||
|
||||
// KEINE IP-Adressen.
|
||||
//
|
||||
// `ADMIN_HOSTS` darf ausdrücklich eine nackte IP führen — sie ist der
|
||||
// Wiederzugang zur Konsole, wenn ein Name einmal nicht auflöst. Aber für
|
||||
// eine IP stellt Let's Encrypt kein Zertifikat aus, also steht sie in
|
||||
// einer Zertifikatsübersicht nur als dauerhaft roter Eintrag, den
|
||||
// niemand beheben kann.
|
||||
//
|
||||
// Der erste Filter verlangte bloß einen Punkt — `127.0.0.1` hat drei.
|
||||
// Deshalb hier beides: die Adressprüfung UND die Bedingung, dass die
|
||||
// letzte Marke keine Zahl ist. Eine Endung ist nie numerisch, und das
|
||||
// fängt auch die Formen ab, die `FILTER_VALIDATE_IP` durchlässt.
|
||||
if (filter_var($host, FILTER_VALIDATE_IP) !== false) {
|
||||
return;
|
||||
}
|
||||
|
||||
$letzteMarke = substr($host, strrpos($host, '.') + 1);
|
||||
if ($letzteMarke === '' || ctype_digit($letzteMarke)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Konsole gewinnt gegen öffentlich, wenn ein Name in beiden Listen
|
||||
// steht: die engere Aussage ist die richtige.
|
||||
if (($found[$host] ?? null) !== 'console') {
|
||||
|
|
|
|||
|
|
@ -198,51 +198,3 @@ it('counts what is valid, what expires soon and what is broken', function () {
|
|||
->and($summary['soon'])->toBe(1)
|
||||
->and($summary['failing'])->toBe(1);
|
||||
});
|
||||
|
||||
/**
|
||||
* Der Fund vom Live-Server: `127.0.0.1` stand in der Übersicht, als Konsole,
|
||||
* mit „Kein gültiges Zertifikat: Connection refused".
|
||||
*
|
||||
* Er kam aus `ADMIN_HOSTS`, wo eine nackte IP als Wiederzugang ausdrücklich
|
||||
* stehen darf. Der erste Filter verlangte nur einen Punkt — davon hat
|
||||
* `127.0.0.1` drei. Für eine IP stellt Let's Encrypt kein Zertifikat aus, also
|
||||
* war das ein dauerhaft roter Eintrag, den niemand beheben kann.
|
||||
*/
|
||||
it('keeps IP addresses out of a certificate overview', function () {
|
||||
config()->set('admin_access.hosts', ['admin.clupilot.com', '127.0.0.1', '2001:db8::1', '198.51.100.7']);
|
||||
|
||||
$gefunden = array_keys(App\Support\KnownHostnames::all());
|
||||
|
||||
expect($gefunden)->toContain('admin.clupilot.com')
|
||||
->and($gefunden)->not->toContain('127.0.0.1')
|
||||
->and($gefunden)->not->toContain('198.51.100.7')
|
||||
->and($gefunden)->not->toContain('2001:db8::1');
|
||||
});
|
||||
|
||||
/**
|
||||
* Und die Zeile, die schon in der Datenbank steht, geht beim nächsten Abgleich
|
||||
* weg — sonst bliebe mein Fehler auf jeder Installation stehen, die einmal
|
||||
* aktualisiert hat.
|
||||
*/
|
||||
it('clears out a config row that should never have been there', function () {
|
||||
$ip = ProxyHost::create(['hostname' => '127.0.0.1', 'purpose' => 'console', 'source' => 'config']);
|
||||
|
||||
proxyPage();
|
||||
|
||||
expect(ProxyHost::query()->whereKey($ip->id)->exists())->toBeFalse();
|
||||
});
|
||||
|
||||
/**
|
||||
* Aber nichts mit laufendem Zertifikat verschwindet still. Es wird zu einem
|
||||
* Eintrag von Hand, den der Betreiber selbst entfernt — eine Frist, die weiter
|
||||
* läuft, gehört nicht wortlos aus einer Übersicht genommen.
|
||||
*/
|
||||
it('turns a vanished name with a live certificate into a manual entry', function () {
|
||||
$alt = ProxyHost::create(['hostname' => 'frueher.clupilot.com', 'purpose' => 'public', 'source' => 'config']);
|
||||
$alt->forceFill(['certificate_expires_at' => now()->addDays(40), 'certificate_checked_at' => now()])->save();
|
||||
|
||||
proxyPage();
|
||||
|
||||
expect($alt->fresh()->isFromConfig())->toBeFalse()
|
||||
->and(ProxyHost::query()->whereKey($alt->id)->exists())->toBeTrue();
|
||||
});
|
||||
|
|
|
|||
Loading…
Reference in New Issue