Support cross-origin frontends alongside same-origin setups

- django-cors-headers with env-driven CORS_ALLOWED_ORIGINS,
  CORS_ALLOW_ALL_ORIGINS, CORS_ALLOW_CREDENTIALS and CSRF_TRUSTED_ORIGINS;
  same-origin traffic is unaffected and a disallowed origin gets no CORS
  headers. Token auth needs no cookies, so credentials stay off by default.
- TRUST_PROXY_HEADERS=true lets a TLS-terminating proxy supply
  X-Forwarded-Proto/Host for correct absolute URLs.
- API media URLs (raw/thumbnail/upload/similarity/staged previews) are now
  absolute, built from the request host, so <img>/<video>/fetch() keep
  working when the SPA is served from another origin. Signed URLs are still
  per-user; nothing is stored in the DB.
- The SPA gains VITE_API_BASE (build-time, empty = same-origin) applied by
  a small apiUrl() helper used for XHR/fetch and the few URL fallbacks.

Verified with a throwaway instance: preflight and GET responses carry the
allowed origin, foreign origins get nothing, media GETs include CORS for
cross-origin fetch(), and payload URLs use the request host (dev :8000
unchanged).
This commit is contained in:
2026-09-17 22:50:12 -05:00
parent 98a674d55e
commit 16907c39ca
16 changed files with 139 additions and 52 deletions
+4 -4
View File
@@ -15,7 +15,7 @@ import {
import { Link } from "react-router-dom";
import { Button, EmptyState, Spinner, inputClass } from "@/components/ui";
import { api, authHeaders, errorMessage, uploadFile } from "@/lib/api";
import { api, authHeaders, apiUrl, errorMessage, uploadFile } from "@/lib/api";
import { cn } from "@/lib/cn";
import {
E621Error,
@@ -398,10 +398,10 @@ function MetadataModal({
className="flex items-center gap-3 rounded-md border border-ctp-surface0 bg-ctp-surface0/40 p-2"
>
<img
src={
src={apiUrl(
match.thumbnail_url ??
`/api/files/${match.j_id}/thumbnail/`
}
`/api/files/${match.j_id}/thumbnail/`,
)}
alt={match.j_id}
loading="lazy"
className="h-12 w-12 shrink-0 rounded object-cover"