Skip to content

Photo System

The site has three separate photo pipelines, each with a different purpose, storage backend, and trust model. They are not interchangeable — don’t conflate them.

#SubsystemDirectionTrust model
1Catalog / product imageryread (display)public, hotlink-protected
2Claim photoswrite (buyer upload)public after upload
3Sponsor logoswrite (sponsor upload)private, reviewed

1. Catalog / product imagery — read path

Section titled “1. Catalog / product imagery — read path”

The display layer for emblems and products. Origin files live on disk; delivery runs through an edge image service that resizes and caches variants (thumb / medium / hero) so the browser fetches the smallest size that satisfies the layout width.

  • Responsive srcset across variants.
  • Hotlink protection at the edge.
  • A drop-in image component, plus a protected-image variant that adds casual-theft deterrents (disables right-click / drag / long-press). The protected variant explicitly does not stop screenshots, devtools, or headless scrapers.

When a buyer claims a physical piece, they can upload one photo of it.

  • The claim must already exist and be in the claimed state (claim first, then photo).
  • One photo per claim.
  • JPG / PNG / WebP only, size-capped.
  • Magic-byte validation — the declared content-type is not trusted on its own.
  • Rate limited per request fingerprint.

Uploaded photos are served publicly and linked back to the claim record.

3. Sponsor logos — write path (private, reviewed)

Section titled “3. Sponsor logos — write path (private, reviewed)”

Sponsor / supporter logo intake. Stricter than claim photos.

  • Token-gated — requires a valid intake token tied to a contribution.
  • PNG and SVG only. PNG validated by magic bytes; SVG sanitized against script / embed / event-handler / external-reference vectors (anti-XSS / anti-XXE) before it is ever stored.
  • Roles: primary / secondary logo; capped per contribution; no silent replace.
  • Rate limited per fingerprint.
  • Stored in a private bucket and held for manual review before use.

  • Magic-byte signature sniffing for uploaded images — never trust the declared content-type.
  • Per-route rate limiting keyed on a request fingerprint.
  • Constant-time token comparison for token-gated flows.