-- 0043: site_settings — Spalten-Grant für anon einschränken (SECURITY-FIX) -- -- Bisher: Policy `public_read_site_settings` (using true) erlaubt anon das -- Lesen der site_settings-Zeile. RLS-Policies filtern aber KEINE Spalten — -- das macht nur GRANT. site_settings wurde (anders als employees in 0014, -- persons in 0025) nie spaltenweise eingeschränkt. Dadurch konnte jeder mit -- dem öffentlichen anon-Key per Supabase-REST die Geheimnisse auslesen: -- Apple-Wallet-Zertifikat (.p12) + Passphrase, Google-Service-Account-JSON, -- AI-API-Keys (Anthropic/OpenAI/OpenRouter), Phone-Tokens (api/lookup/ -- webhook) und der License-Key. -- -- Robuste Umsetzung (Block-Liste statt fester Spalten-Liste): anon den -- Vollzugriff entziehen, dann per Katalog-Lookup ALLE existierenden Spalten -- AUSSER den Geheimnis-Spalten freigeben. Funktioniert unabhängig vom -- Schema-Stand der jeweiligen Mandanten-DB (Prod, Demo, künftige Kunden) — -- eine feste Spalten-Liste bricht, sobald eine DB nicht voll migriert ist. -- -- WICHTIG (Betrieb): Die bereits exponierten Geheimnisse gelten als -- kompromittiert und müssen rotiert werden (OpenRouter-Key, License-Key, -- Apple-Pass-Zertifikat + Passphrase, ggf. weitere befüllte Keys/Tokens). -- HINWEIS für neue Geheimnis-Spalten: unbedingt in die Block-Liste unten -- aufnehmen, sonst werden sie automatisch anon-lesbar. revoke all on public.site_settings from anon; do $$ declare v_cols text; begin select string_agg(quote_ident(column_name), ', ') into v_cols from information_schema.columns where table_schema = 'public' and table_name = 'site_settings' and column_name not in ( -- Geheimnis-Spalten — NUR über Service-Role lesbar: 'ai_anthropic_key', 'ai_openai_key', 'ai_openrouter_key', 'apple_pass_cert_p12', 'apple_pass_passphrase', 'apple_pass_type_id', 'google_wallet_service_account_json', 'phone_api_token', 'phone_lookup_token', 'phone_webhook_secret', 'license_key' ); execute 'grant select (' || v_cols || ') on public.site_settings to anon'; end $$;