diff --git a/api/index.php b/api/index.php index a84534f..06ca924 100644 --- a/api/index.php +++ b/api/index.php @@ -3,33 +3,71 @@ declare(strict_types=1); -$apibasedir = $_SERVER['DOCUMENT_ROOT']; // bei dir: /.../projects/usbcheck/staging/api +$apibasedir = $_SERVER['DOCUMENT_ROOT']; require $apibasedir . '/../config/fileload.php'; -// Basis-Header (CORS, JSON) -header('Content-Type: application/json; charset=utf-8'); -header('Access-Control-Allow-Origin: *'); +/* +|-------------------------------------------------------------------------- +| CORS – Dynamische Freigabe +|-------------------------------------------------------------------------- +| WICHTIG: credentials:true verbietet Access-Control-Allow-Origin: * +| Darum erlauben wir nur explizite Frontend-Domains. +*/ +$allowedOrigins = [ + 'https://staging.usbcheck.it', + 'https://usbcheck.it', + 'http://localhost', // optional für lokale Entwicklung +]; + +$origin = $_SERVER['HTTP_ORIGIN'] ?? ''; + +if (in_array($origin, $allowedOrigins, true)) { + // Dynamische Freigabe der erlaubten Domain + header("Access-Control-Allow-Origin: {$origin}"); + header("Vary: Origin"); // wichtig gegen Proxy-Caching-Probleme +} else { + // Fallback: Staging-Domain + header("Access-Control-Allow-Origin: https://staging.usbcheck.it"); + header("Vary: Origin"); +} + +// Weitere CORS-Header +header('Access-Control-Allow-Credentials: true'); header('Access-Control-Allow-Methods: GET, POST, OPTIONS'); header('Access-Control-Allow-Headers: Content-Type, Authorization, X-Requested-With'); +// JSON Response Header +header('Content-Type: application/json; charset=utf-8'); + +// OPTIONS – Preflight-Anfrage vorzeitig beenden if ($_SERVER['REQUEST_METHOD'] === 'OPTIONS') { http_response_code(204); exit; } -// Pfad aus der URL holen +/* +|-------------------------------------------------------------------------- +| Routing vorbereiten +|-------------------------------------------------------------------------- +*/ + $uri = parse_url($_SERVER['REQUEST_URI'] ?? '/', PHP_URL_PATH); $path = rtrim($uri, '/'); + if ($path === '') { $path = '/'; } -// Root-Info (optional) +/* +|-------------------------------------------------------------------------- +| Root-Info (optional) +|-------------------------------------------------------------------------- +*/ if ($path === '/') { echo json_encode([ - 'ok' => true, - 'service' => 'usbcheck-api', - 'version' => 1, + 'ok' => true, + 'service' => 'usbcheck-api', + 'version' => 1, 'endpoints' => [ '/v1/quickcheck', '/v1/browser.quick.test', @@ -39,10 +77,15 @@ if ($path === '/') { exit; } -// Routing nach Bereich +/* +|-------------------------------------------------------------------------- +| Versioniertes Routing /v1/* +|-------------------------------------------------------------------------- +*/ if (str_starts_with($path, '/v1/')) { + // alles hinter /v1/ in Segmente zerlegen - $rel = substr($path, strlen('/v1/')); // z.B. "browser.quick.test" oder "quickcheck" oder "foo/bar" + $rel = substr($path, strlen('/v1/')); // z.B. "browser.quick.test" $rel = ltrim($rel, '/'); $segments = $rel === '' ? [] : explode('/', $rel); @@ -51,12 +94,21 @@ if (str_starts_with($path, '/v1/')) { exit; } +/* +|-------------------------------------------------------------------------- +| Internal API /internal/* +|-------------------------------------------------------------------------- +*/ if (str_starts_with($path, '/internal/')) { require_once $apibasedir . '/router/router.internal.php'; exit; } -// Fallback: unbekannter Bereich +/* +|-------------------------------------------------------------------------- +| Fallback: Unbekannter Bereich +|-------------------------------------------------------------------------- +*/ http_response_code(404); echo json_encode([ 'ok' => false,