diff --git a/api/index.php b/api/index.php index b459fb6..dae2550 100644 --- a/api/index.php +++ b/api/index.php @@ -61,6 +61,23 @@ if (($_GET['action'] ?? '') === 'app_bootstrap') { exit; } +// ── HA discovery (no token) — lets HACS config flow find the server ─────────── +if (($_GET['action'] ?? '') === 'ha_info' && evershelfApiTokenRequired() && !evershelfApiTokenValid()) { + header('Content-Type: application/json; charset=utf-8'); + $uniqueId = 'evershelf_' . substr(md5(__DIR__ . php_uname('n')), 0, 12); + echo json_encode([ + 'name' => 'EverShelf', + 'instance' => env('INSTANCE_NAME', php_uname('n')), + 'version' => _appVersion(), + 'unique_id' => $uniqueId, + 'has_token' => true, + 'api_token_required' => true, + 'api_version' => 1, + 'items_count' => null, + ], JSON_UNESCAPED_UNICODE); + exit; +} + // ── Google Drive OAuth callback — returns HTML, not JSON ────────────────────── if (($_GET['action'] ?? '') === 'gdrive_oauth_callback') { _gdriveHandleOAuthCallback(); @@ -1939,7 +1956,8 @@ function haGetInfo(PDO $db): void { 'instance' => env('INSTANCE_NAME', php_uname('n')), 'version' => _appVersion(), 'unique_id' => $uniqueId, - 'has_token' => !empty(env('SETTINGS_TOKEN', '')), + 'has_token' => evershelfApiTokenRequired(), + 'api_token_required' => evershelfApiTokenRequired(), 'api_version' => 1, 'items_count' => $itemsCount, ], JSON_UNESCAPED_UNICODE); diff --git a/api/lib/security.php b/api/lib/security.php index 0344780..15fe07b 100644 --- a/api/lib/security.php +++ b/api/lib/security.php @@ -28,6 +28,13 @@ function evershelfGetProvidedApiToken(): string { if (isset($_GET['api_token'])) { return (string)$_GET['api_token']; } + // Home Assistant ha-evershelf sends Authorization: Bearer (legacy) + $authHeader = $_SERVER['HTTP_AUTHORIZATION'] + ?? $_SERVER['REDIRECT_HTTP_AUTHORIZATION'] + ?? ''; + if (preg_match('/^Bearer\s+(\S+)/i', $authHeader, $m)) { + return $m[1]; + } return evershelfGetProvidedApiTokenFromHeaders(); }