mirror of
https://github.com/J3vb/OwnCord.git
synced 2026-09-03 03:50:00 +03:00
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>
47 lines
1.4 KiB
Go
47 lines
1.4 KiB
Go
package api
|
|
|
|
import (
|
|
"context"
|
|
"net/http"
|
|
)
|
|
|
|
// HandleMetricsForTest exposes handleMetrics for use in external tests.
|
|
var HandleMetricsForTest = handleMetrics
|
|
|
|
// HandleLiveKitHealthForTest exposes handleLiveKitHealth for use in external tests.
|
|
func HandleLiveKitHealthForTest(healthCheck func(context.Context) (bool, error)) http.HandlerFunc {
|
|
// Inline the logic since handleLiveKitHealth requires a *ws.Hub.
|
|
return func(w http.ResponseWriter, r *http.Request) {
|
|
ok, err := healthCheck(r.Context())
|
|
if ok {
|
|
writeJSON(w, http.StatusOK, livekitHealthResponse{
|
|
Status: "ok",
|
|
LiveKitReachable: true,
|
|
})
|
|
return
|
|
}
|
|
|
|
errMsg := "unknown"
|
|
if err != nil {
|
|
errMsg = err.Error()
|
|
}
|
|
writeJSON(w, http.StatusServiceUnavailable, livekitHealthResponse{
|
|
Status: "degraded",
|
|
LiveKitReachable: false,
|
|
Error: errMsg,
|
|
})
|
|
}
|
|
}
|
|
|
|
// IsPrivateIPForTest exposes isPrivateIP for use in external tests.
|
|
var IsPrivateIPForTest = isPrivateIP
|
|
|
|
// SetGIFUpstreamForTest points the GIF proxy at a stub upstream and returns a
|
|
// restore func. The production transport uses the SSRF-guarded dialer, which
|
|
// refuses loopback addresses, so tests must supply their own client too.
|
|
func SetGIFUpstreamForTest(baseURL string, client *http.Client) func() {
|
|
prevBase, prevClient := gifAPIBase, gifClient
|
|
gifAPIBase, gifClient = baseURL, client
|
|
return func() { gifAPIBase, gifClient = prevBase, prevClient }
|
|
}
|