- Domain-Entity polymorph (Reseller ODER Firma) - TenantResolver: Host → Plattform / reseller.portal / firma.reseller.portal / verifizierte Custom-Domain - Öffentliches GET /api/branding (Name, Ebene, Farben, Logo) nach Host - TLS-Gate nutzt TenantResolver (nur bekannte Hosts → Zertifikat) - Frontend: Branding-Store lädt vor Mount, färbt Theme um, TenantBrand- Komponente (Logo/Name je Tenant), Login zeigt Tenant - Vite-Proxy reicht Original-Host durch (lokales White-Label-Testing) Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
34 lines
1.1 KiB
PHP
34 lines
1.1 KiB
PHP
<?php
|
|
|
|
namespace App\Controller;
|
|
|
|
use App\Service\TenantResolver;
|
|
use Symfony\Component\HttpFoundation\Request;
|
|
use Symfony\Component\HttpFoundation\Response;
|
|
use Symfony\Component\Routing\Attribute\Route;
|
|
|
|
/**
|
|
* On-Demand-TLS-Autorisierung für Caddy (KONZEPT §11): Caddy fragt vor dem
|
|
* Ausstellen eines Let's-Encrypt-Zertifikats hier nach, ob die Domain erlaubt ist.
|
|
* Erlaubt = jeder Host, den der TenantResolver kennt (Portal-Domain, Reseller-/
|
|
* Firmen-Standard-Subdomain oder verifizierte Custom-Domain).
|
|
* 200 → ausstellen, sonst ablehnen (verhindert unbegrenzte Zertifikatsanfragen).
|
|
*/
|
|
final class TlsCheckController
|
|
{
|
|
#[Route('/internal/tls-allowed', name: 'tls_allowed', methods: ['GET'])]
|
|
public function __invoke(Request $request, TenantResolver $resolver): Response
|
|
{
|
|
$host = (string) $request->query->get('domain');
|
|
if ('' === trim($host)) {
|
|
return new Response('missing domain', 400);
|
|
}
|
|
|
|
if (null !== $resolver->resolve($host)) {
|
|
return new Response('ok', 200);
|
|
}
|
|
|
|
return new Response('not allowed', 403);
|
|
}
|
|
}
|