bind-hosts nimmt keinen Wert mehr an, der kein Hostname sein kann
parent
5967c56d16
commit
620539a512
|
|
@ -53,6 +53,15 @@ class BindHosts extends Command
|
|||
'FILES_HOST' => (string) $this->option('files'),
|
||||
];
|
||||
|
||||
foreach ($wanted as $key => $value) {
|
||||
if ($value !== '' && ! $this->isHostList($value)) {
|
||||
$this->error("{$key}: „{$value}“ ist kein Hostname.");
|
||||
$this->line('Erwartet wird ein Name wie app.example.com, mehrere kommagetrennt.');
|
||||
|
||||
return self::FAILURE;
|
||||
}
|
||||
}
|
||||
|
||||
$missing = [];
|
||||
|
||||
foreach ($wanted as $key => $value) {
|
||||
|
|
@ -113,6 +122,43 @@ class BindHosts extends Command
|
|||
return self::SUCCESS;
|
||||
}
|
||||
|
||||
/** Eine Komma-Liste, in der JEDER Eintrag ein Hostname ist. */
|
||||
private function isHostList(string $value): bool
|
||||
{
|
||||
$names = array_map('trim', explode(',', $value));
|
||||
|
||||
if ($names === [] || in_array('', $names, true)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
foreach ($names as $name) {
|
||||
if (! $this->isHost($name)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Dasselbe Muster, das der root-eigene Helfer in `apply-proxy-hosts`
|
||||
* benutzt, bevor er einen Namen in die Proxy-Konfiguration schreibt
|
||||
* (deploy/install-agent.sh).
|
||||
*
|
||||
* Der Anlass ist konkret: `[www.example.com](https://www.example.com)` ist
|
||||
* als Hostname offensichtlich Unsinn und wurde trotzdem geschrieben, weil
|
||||
* die Zeile die Form KEY=value hatte. Das Repo kennt diese Falle schon —
|
||||
* RestrictConsoleNetwork::isNetwork() gibt es, weil ein Eintrag, der nichts
|
||||
* trifft, sonst „stored happily and reports success".
|
||||
*/
|
||||
private function isHost(string $name): bool
|
||||
{
|
||||
return (bool) preg_match(
|
||||
'/^[a-z0-9]([a-z0-9-]{0,61}[a-z0-9])?(\.[a-z0-9]([a-z0-9-]{0,61}[a-z0-9])?)+$/',
|
||||
$name,
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Der Wert eines Schlüssels, oder '' wenn er fehlt ODER leer ist.
|
||||
*
|
||||
|
|
|
|||
|
|
@ -111,20 +111,51 @@ it('sagt es, wenn schon alles steht, statt eine Sicherung anzulegen', function (
|
|||
expect(glob($this->envPath.'.bak-*'))->toBeEmpty();
|
||||
});
|
||||
|
||||
it('schreibt einen Wert wörtlich, auch wenn er wie ein Rückverweis aussieht', function () {
|
||||
it('lehnt einen Wert ab, der wie ein Rückverweis aussieht, statt ihn zu verschlucken', function () {
|
||||
// SITE_HOST steht schon leer da — genau das, was .env.example wirklich
|
||||
// ausliefert, und der Pfad, auf dem apply() eine vorhandene Zeile per
|
||||
// preg_replace ersetzt statt sie nur anzuhängen.
|
||||
file_put_contents($this->envPath, "APP_URL=https://app.example.test\nSITE_HOST=\n");
|
||||
|
||||
// `$1` und `\1` sind das, was preg_replace im ERSATZ als Rückverweis
|
||||
// deutet und still verschluckt. Diese Datei hält jedes Geheimnis der
|
||||
// Installation — was hier ankommt, muss ankommen wie eingegeben.
|
||||
// deutet und still verschluckt hätte — apply() schützt genau davor. Seit
|
||||
// der Hostnamen-Prüfung kommt der Wert dort aber gar nicht mehr an: `$`
|
||||
// und `\` sind in keinem Hostnamen erlaubt, also weist die Prüfung ihn
|
||||
// vorher zurück, statt ihn (unbeschädigt oder nicht) zu schreiben.
|
||||
$this->artisan('clupilot:bind-hosts', [
|
||||
'--site' => 'www.example.test$1,foo\1bar',
|
||||
'--force' => true,
|
||||
])->assertSuccessful();
|
||||
])->assertFailed();
|
||||
|
||||
expect(file_get_contents($this->envPath))
|
||||
->toContain('SITE_HOST=www.example.test$1,foo\1bar');
|
||||
->toBe("APP_URL=https://app.example.test\nSITE_HOST=\n")
|
||||
->and(glob($this->envPath.'.bak-*'))->toBeEmpty();
|
||||
});
|
||||
|
||||
it('lehnt ab, was kein Hostname sein kann, und schreibt nichts', function () {
|
||||
file_put_contents($this->envPath, "APP_URL=https://app.example.test\n");
|
||||
|
||||
// Genau der Wert, der auf der Produktivmaschine landete. Er ist als
|
||||
// Hostname offensichtlich Unsinn und wurde trotzdem geschrieben, weil
|
||||
// EnvFileEditor nur prueft, ob die ZEILE die Form KEY=value hat.
|
||||
$this->artisan('clupilot:bind-hosts', [
|
||||
'--site' => '[www.example.test](https://www.example.test)',
|
||||
'--force' => true,
|
||||
])->assertFailed();
|
||||
|
||||
expect(file_get_contents($this->envPath))->not->toContain('SITE_HOST')
|
||||
->and(glob($this->envPath.'.bak-*'))->toBeEmpty();
|
||||
});
|
||||
|
||||
it('prüft jeden Namen einer Komma-Liste einzeln', function () {
|
||||
file_put_contents($this->envPath, "APP_URL=https://app.example.test\n");
|
||||
|
||||
// Der erste Name ist gültig — geschrieben werden darf trotzdem nichts,
|
||||
// sonst stünde die halbe Liste in der Datei.
|
||||
$this->artisan('clupilot:bind-hosts', [
|
||||
'--site' => 'www.example.test,nicht gültig',
|
||||
'--force' => true,
|
||||
])->assertFailed();
|
||||
|
||||
expect(file_get_contents($this->envPath))->not->toContain('SITE_HOST');
|
||||
});
|
||||
|
|
|
|||
Loading…
Reference in New Issue