Files
ladill-servers/app/Jobs/ProvisionDomainZoneJob.php
isaaccladandCursor b6c8ac343f Extract Ladill Servers as standalone app at servers.ladill.com.
VPS and dedicated server ordering, managed panels, SSO, billing, and launcher integration — forked from hosting infrastructure with server-focused routes and dashboard.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-06-06 19:18:30 +00:00

116 lines
3.5 KiB
PHP

<?php
namespace App\Jobs;
use App\Models\Domain;
use App\Models\DomainDkimKey;
use App\Models\DomainNsCheck;
use App\Jobs\ProvisionDomainSlaveZoneJob;
use App\Services\Dns\PowerDnsClient;
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Bus\Dispatchable;
use Illuminate\Http\Client\RequestException;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Queue\SerializesModels;
use Illuminate\Support\Facades\File;
use Illuminate\Support\Str;
class ProvisionDomainZoneJob implements ShouldQueue
{
use Dispatchable;
use InteractsWithQueue;
use Queueable;
use SerializesModels;
public int $tries = 5;
public int $backoff = 60;
public function __construct(public int $domainId)
{
}
public function handle(PowerDnsClient $client): void
{
$domain = Domain::query()->find($this->domainId);
if (! $domain) {
return;
}
// Ensure DKIM keys exist before provisioning zone
$this->ensureDkimKeys($domain);
try {
$client->ensureZone($domain);
$this->logCheck($domain, 'success', 'PDNS zone provisioned successfully.');
ProvisionDomainSlaveZoneJob::dispatch($domain->id);
} catch (RequestException $exception) {
$this->logCheck($domain, 'failed', $exception->getMessage());
throw $exception;
}
}
private function ensureDkimKeys(Domain $domain): void
{
$existing = DomainDkimKey::query()
->where('domain_id', $domain->id)
->where('status', 'active')
->latest('id')
->first();
if ($existing) {
return;
}
$prefix = (string) config('mailinfra.dkim_selector_prefix', 'ladill');
$selector = Str::lower(trim($prefix)) ?: 'ladill';
$selector .= '1';
$config = [
'digest_alg' => 'sha512',
'private_key_bits' => 2048,
'private_key_type' => OPENSSL_KEYTYPE_RSA,
];
$res = openssl_pkey_new($config);
openssl_pkey_export($res, $privateKey);
$details = openssl_pkey_get_details($res);
$publicKey = $details['key'] ?? '';
$publicKey = preg_replace('/-----BEGIN PUBLIC KEY-----|-----END PUBLIC KEY-----|\s/', '', $publicKey);
$privatePath = null;
if (is_string($privateKey) && trim($privateKey) !== '') {
$safeHost = Str::slug($domain->host, '_');
$directory = storage_path('app/mail/dkim');
File::ensureDirectoryExists($directory);
$privatePath = $directory.'/'.$safeHost.'_'.$selector.'.key';
File::put($privatePath, $privateKey);
}
DomainDkimKey::query()->create([
'domain_id' => $domain->id,
'selector' => $selector,
'public_key_txt' => $publicKey,
'private_key_path' => $privatePath,
'status' => 'active',
]);
}
private function logCheck(Domain $domain, string $result, string $notes): void
{
DomainNsCheck::create([
'domain_id' => $domain->id,
'check_type' => 'pdns_provision',
'result' => $result,
'status_before' => (string) $domain->status,
'status_after' => (string) $domain->status,
'state_before' => (string) ($domain->onboarding_state ?? ''),
'state_after' => (string) ($domain->onboarding_state ?? ''),
'notes' => $notes,
'checked_at' => now(),
]);
}
}