Installer: sechs Bildschirme, und eine Datei davor
/install fuehrt von einer leeren Installation zu einer Website: Systempruefung, Datenbank (SQLite oder MySQL, Verbindung sofort geprueft), Migration im Prozess ohne Konsole, Website mit Startseite, Bereichen, Menue sowie Impressum und Datenschutzgeruest, erstes Konto, Abschlussliste. Jeder Schritt schreibt sein Ergebnis sofort, damit ein Neuladen nichts verliert. Gesperrt wird ueber den Zustand der Datenbank - gibt es ein Konto, antwortet /install mit 404. Eine Datei koennte jemand loeschen. Solange nichts installiert ist, fuehrt jede Adresse zum Installer statt zu einem 500 aus einer fehlenden Tabelle. Und weil ohne APP_SECRET nicht einmal die Seite bootet, die das erklaeren wuerde, erzeugt der erste Start das Geheimnis selbst. scripts/install.php ist die einzelne Datei davor: Adresse und SHA-256 stehen darin (vom Buildskript eingetragen), ohne passende Pruefsumme wird nicht entpackt, jeder Archiveintrag wird gegen das Zielverzeichnis geprueft, und danach loescht sie sich selbst. Geprueft: 379 Tests unter PHP 8.2 und 8.4, darunter der ganze Ablauf durch die HTTP-Schicht, neun ZIP-Slip-Varianten, axe ohne Verstoss auf allen Installationsbildschirmen, und das entpackte Releasearchiv startet in den Installer. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
1 parent
c3bff7d936
commit
e34b4dca67
25 files changed
+1937
-7
No files matched your search
@@ -15,7 +15,10 @@
|
||||
* would mean an archive with PHPUnit in it.
|
||||
*/
|
||||
$root = dirname(__DIR__);
|
||||
$options = getopt('', ['out::', 'keep-dev']);
|
||||
$options = getopt('', ['out::', 'keep-dev', 'url::']);
|
||||
// Wohin das Archiv beim Veröffentlichen gelegt wird. Steht fest in install.php, deshalb muss
|
||||
// sie hier bekannt sein - eine Adresse, die erst im Browser abgefragt wird, wäre eine Lücke.
|
||||
$releaseBase = rtrim($options['url'] ?? 'https://git.kant-it.de/kantarci/KantSites/releases/download', '/');
|
||||
$outDirectory = $root.'/'.trim($options['out'] ?? 'var/releases', '/');
|
||||
$version = trim((string) file_get_contents($root.'/VERSION'));
|
||||
if (1 !== preg_match('/^\d+\.\d+\.\d+$/D', $version)) {
|
||||
@@ -87,6 +90,14 @@ foreach ($include as $entry) {
|
||||
$files += $copy($root.'/'.$entry, $staging.'/'.$entry);
|
||||
}
|
||||
}
|
||||
|
||||
// Die .env des Entwicklungsrechners gehört nicht in ein Release; gebraucht wird trotzdem eine,
|
||||
// denn ohne sie bootet die Anwendung nicht einmal so weit, dass der Installer erscheint. Also
|
||||
// wird die Vorlage zur .env des Releases - mit Produktionswerten und ohne Geheimnis. Das
|
||||
// Geheimnis erzeugt der erste Aufruf selbst, die Zugangsdaten schreibt der Installer nach
|
||||
// .env.local.
|
||||
copy($root.'/.env.example', $staging.'/.env');
|
||||
++$files;
|
||||
echo "Quelldateien: {$files}\n";
|
||||
|
||||
// The dependencies, without the development ones - that is the whole point of building here.
|
||||
@@ -137,4 +148,16 @@ file_put_contents($archive.'.sha256', $hash.' '.basename($archive)."\n");
|
||||
printf("\nArchiv: %s\n", $archive);
|
||||
printf("Dateien: %d, Größe: %.1f MB\n", $entries, filesize($archive) / 1048576);
|
||||
printf("SHA-256: %s\n", $hash);
|
||||
echo "\nDie Prüfsumme gehört in install.php, damit ein manipuliertes Archiv nicht entpackt wird.\n";
|
||||
|
||||
// Und der einzelne Dateidownload: dieselbe install.php, nur mit eingetragener Adresse und
|
||||
// Prüfsumme. Ohne beides verweigert sie die Arbeit, deshalb entsteht sie erst hier.
|
||||
$installer = strtr((string) file_get_contents($root.'/scripts/install.php'), [
|
||||
"const KANT_ARCHIVE_URL = '';" => sprintf("const KANT_ARCHIVE_URL = '%s';", $releaseBase.'/v'.$version.'/'.basename($archive)),
|
||||
"const KANT_ARCHIVE_SHA256 = '';" => sprintf("const KANT_ARCHIVE_SHA256 = '%s';", $hash),
|
||||
"const KANT_VERSION = '';" => sprintf("const KANT_VERSION = '%s';", $version),
|
||||
]);
|
||||
file_put_contents($outDirectory.'/install.php', $installer);
|
||||
|
||||
printf("Installer: %s (lädt %s)\n", $outDirectory.'/install.php', $releaseBase.'/v'.$version.'/'.basename($archive));
|
||||
echo "\nBeides gehört auf die Releaseseite: das Archiv unter genau dieser Adresse, und install.php zum Herunterladen.\n";
|
||||
echo "Die Prüfsumme steckt jetzt in install.php, damit ein manipuliertes Archiv nicht entpackt wird.\n";
|
||||
Reference in new issue
Block a user