argument('domainId')); if (!$domain) { $this->error('Domain nicht gefunden.'); return self::FAILURE; } // Host bestimmen $host = trim($this->option('host') ?: Hostnames::mta()); if (!str_contains($host, '.')) { $this->error("Ungültiger Host: {$host}"); return self::FAILURE; } $service = $this->option('service') ?: '_25._tcp'; $usage = (int) $this->option('usage'); $selector = (int) $this->option('selector'); $matching = (int) $this->option('matching'); // Let’s Encrypt Pfad (ggf. anpassen, falls anderes CA/Verzeichnis) $certPath = "/etc/letsencrypt/live/{$host}/fullchain.pem"; if (!is_file($certPath)) { $this->error("Zertifikat nicht gefunden: {$certPath}"); $this->line('Tipp: LE deploy hook/renewal erst durchlaufen lassen oder Pfad anpassen.'); return self::FAILURE; } // Hash über SPKI (selector=1) + SHA-256 (matching=1) $cmd = "openssl x509 -in ".escapeshellarg($certPath)." -noout -pubkey" . " | openssl pkey -pubin -outform DER" . " | openssl dgst -sha256"; $proc = Process::fromShellCommandline($cmd); $proc->run(); if (!$proc->isSuccessful()) { $this->error('Fehler bei der Hash-Erzeugung (openssl).'); $this->line($proc->getErrorOutput()); return self::FAILURE; } $hash = preg_replace('/^SHA256\(stdin\)=\s*/', '', trim($proc->getOutput())); $record = TlsaRecord::updateOrCreate( [ 'domain_id' => $domain->id, 'host' => $host, 'service' => $service, ], [ 'usage' => $usage, 'selector' => $selector, 'matching' => $matching, 'hash' => $hash, 'cert_path' => $certPath, ] ); $this->info('✅ TLSA gespeichert'); $this->line(sprintf( '%s.%s IN TLSA %d %d %d %s', $record->service, $record->host, $record->usage, $record->selector, $record->matching, $record->hash )); return self::SUCCESS; } }