CluPilotCloud/app/Provisioning/Steps/Customer/ConfigureInstanceMail.php

97 lines
3.6 KiB
PHP

<?php
namespace App\Provisioning\Steps\Customer;
use App\Models\ProvisioningRun;
use App\Provisioning\StepResult;
use App\Services\Mail\GuestMailConfig;
use App\Services\Proxmox\ProxmoxClient;
use App\Support\NextcloudOcc;
/**
* Bringt der Nextcloud eines Kunden bei, Mail zu verschicken.
*
* Bis hierher konnte sie es NICHT — weder die Bereitstellung noch die
* Compose-Datei der Vorlage setzten je einen Versand. Damit verschickte jede
* Kundeninstanz gar nichts: keine Freigabe-Benachrichtigung, keine
* Aktivitaetsmeldung, kein "Passwort vergessen". Still, ohne Fehlermeldung.
*
* Das ist die Voraussetzung fuer die Mitarbeiterverwaltung: die Einladung an
* einen Mitarbeiter verschickt NEXTCLOUD, nicht CluPilot — nur so entsteht
* das Passwort dort, wo niemand sonst es zu sehen bekommt.
*
* Ohne Server oder Absenderpostfach wird NICHTS geschrieben und der Schritt
* scheitert mit einem Grund. Eine halb eingetragene Mailkonfiguration waere
* schlimmer als keine.
*
* WO DAS SMTP-PASSWORT UEBERALL SICHTBAR IST — ehrlich aufgeschrieben, weil
* ein erster Entwurf es zu verstecken versuchte und das Verstecken nichts
* brachte:
*
* - im Argv des `/bin/sh -c`, das der Gastagent fuer diesen Aufruf startet
* (guestExec baut die ganze Zeile so). Debians `dash` behaelt diesen
* Prozess fuer die volle Dauer des Aufrufs;
* - im Argv von `php occ` im Container;
* - und DAUERHAFT im Klartext in /opt/nextcloud … config/config.php, wo
* Nextcloud es selbst ablegt.
*
* Der dritte Punkt erledigt die ersten beiden: wer die Datei lesen kann, muss
* gar nicht erst in eine Prozessliste schauen. Ein Versteck, das dieselbe
* Person nicht aussperrt, ist keines — und ein Kommentar, der eines
* behauptet, haelt den Naechsten vom Nachsehen ab.
*
* Die Eingrenzung liegt deshalb in der Infrastruktur, nicht hier: das
* Versandkonto kann nur senden, der Versandport nimmt nur die eigenen
* Hostadressen an, und der Mailserver drosselt je Konto. Was hier gilt und
* geprueft wird, ist etwas anderes: der Wert wird maskiert, damit er keinen
* zweiten Befehl starten kann.
*/
class ConfigureInstanceMail extends CustomerStep
{
public function __construct(private ProxmoxClient $pve) {}
public function key(): string
{
return 'configure_instance_mail';
}
public function maxDuration(): int
{
return 120;
}
public function execute(ProvisioningRun $run): StepResult
{
$instance = $this->instance($run);
if ($instance === null) {
return StepResult::fail('instance_missing');
}
$config = GuestMailConfig::for($instance);
if (! $config->available()) {
return StepResult::fail($config->problem() ?? 'mail_unavailable');
}
$pve = $this->pve->forHost($instance->host);
// Der Schluessel ist ein fester occ-Name aus GuestMailConfig::values(),
// keine Benutzereingabe — genauso unmaskiert wie 'files default_quota'
// in ApplyStorageQuota. Maskiert wird nur der WERT, siehe Kopfkommentar.
foreach ($config->values() as $schluessel => $wert) {
$this->guest($pve, $run, NextcloudOcc::command(
'config:system:set '.$schluessel.' --value='.escapeshellarg($wert)
));
}
// Das Passwort wie jeder andere Wert. Verstecken laesst es sich auf
// dieser Maschine nicht — siehe Kopfkommentar.
$this->guest($pve, $run, NextcloudOcc::command(
'config:system:set mail_smtppassword --value='.escapeshellarg($config->password())
));
return StepResult::advance();
}
}