Files
OwnCord/Server/config
J3vbandClaude Fable 5 01f7795557 feat(api): proxy Klipy GIF requests server-side so no key ships to clients
The client held the Klipy key in VITE_KLIPY_API_KEY, which Vite inlines into
the shipped bundle by design — a build variable can never hold a secret. Move
the integration behind the server:

- New authenticated GET /api/v1/gif/search and /api/v1/gif/trending. The key
  comes from the new `gif.api_key` config section (koanf,
  OWNCORD_GIF_API_KEY) and never leaves the server.
- Default-off: with no key, both endpoints return 503 GIF_DISABLED so clients
  can hide the picker instead of showing a broken one. Auth is checked first,
  so anonymous callers cannot probe whether a key is configured.
- Outbound call reuses the existing SSRF-guarded dialer (exported as
  plugin.GuardedDialContext) rather than a bare http.Get: resolve once,
  reject private/loopback/link-local/CGN, dial only vetted IPs. Redirects are
  not followed and the response body is size-capped.
- Only id/title/media_formats.{tinygif,gif}.url are forwarded — decoding into
  the narrow struct is the allowlist, so an upstream that echoed the key
  could not leak it. Upstream errors become a generic 502 and the key is
  redacted from anything that reaches the logs.
- Dedicated `gif:` rate-limit bucket (30/min per IP) so debounced search
  traffic cannot exhaust the shared bucket used by password/TOTP endpoints.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-20 13:29:46 +02:00
..