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(), ]); } }