fix(desktop): read Tenor API key from VITE_TENOR_API_KEY env, no hardcoded credential

This commit is contained in:
byGalax
2026-05-16 18:03:20 +02:00
parent 45bcbb449c
commit f1d9602a76
+17 -5
View File
@@ -7,10 +7,15 @@ const ENDPOINT = 'https://tenor.googleapis.com/v2';
const CLIENT_KEY = 'netralax-chat';
const RECENT_KEY = 'chatapp.gifRecent.v1';
const RECENT_MAX = 24;
// Tenor's public key for browser-side reads. Documented as "anonymous" and
// usable without account binding. Rate-limited at ~3k/day per IP which is
// plenty for a chat app's picker traffic.
const PUBLIC_API_KEY = 'AIzaSyAyimkuYQYF_FXVALexPuGQctUWRURdCYQ';
// Tenor requires a Google API key. Provision one at
// https://developers.google.com/tenor/guides/quickstart and expose it via
// the renderer env var VITE_TENOR_API_KEY (e.g. in apps/desktop/.env.local).
// When unset, every Tenor call throws — the picker degrades to a friendly
// "GIFs gerade nicht verfügbar" message via the consumer's catch.
const API_KEY = (
(import.meta as unknown as { env?: { VITE_TENOR_API_KEY?: string } }).env
?.VITE_TENOR_API_KEY ?? ''
).trim();
export interface GifResult {
id: string;
@@ -44,13 +49,20 @@ function mapResult(r: TenorApiResult): GifResult | null {
}
async function fetchTenor(path: string, params: Record<string, string>): Promise<GifResult[]> {
const search = new URLSearchParams({ key: PUBLIC_API_KEY, client_key: CLIENT_KEY, ...params });
if (!API_KEY) {
throw new Error('tenor_api_key_missing');
}
const search = new URLSearchParams({ key: API_KEY, client_key: CLIENT_KEY, ...params });
const res = await fetch(`${ENDPOINT}/${path}?${search.toString()}`);
if (!res.ok) throw new Error('tenor http ' + res.status);
const json = (await res.json()) as { results?: TenorApiResult[] };
return (json.results ?? []).map(mapResult).filter((x): x is GifResult => x !== null);
}
export function isTenorConfigured(): boolean {
return API_KEY.length > 0;
}
export async function searchGifs(query: string, locale: string = 'de_DE'): Promise<GifResult[]> {
if (!query.trim()) return featuredGifs(locale);
return fetchTenor('search', { q: query, limit: '30', locale });