SPB Git forge

spb/rareindex

Public
54commits 1branches 0releases
7.1 MBsize
maindefault branch
11 days agolast push
TypeScript 61.9% HTML 37.2% SQL 0.7%
1.8 KB · 47 lines typescript
Raw Blame History
1import 'server-only';2import { createHmac } from 'node:crypto';3import { IMAGE_WIDTHS, imageKey, type ImageWidth } from './images-core';45/**6 * Server-side helpers that turn a third-party image URL into signed `/img/…` proxy URLs.7 * Signing (HMAC over the URL with SESSION_SECRET) means only URLs the server chose to render8 * can be proxied — never arbitrary hosts.9 */10function secret(): string {11  return process.env.SESSION_SECRET ?? 'dev-only-session-secret-change-me-please';12}1314export function signImageUrl(url: string): string {15  return createHmac('sha256', secret()).update(`img:${url}`).digest('base64url').slice(0, 20);16}1718export function verifyImageSignature(url: string, sig: string): boolean {19  return sig.length >= 20 && signImageUrl(url) === sig;20}2122function b64url(s: string): string {23  return Buffer.from(s, 'utf8').toString('base64url');24}2526export function imgSrc(url: string, width: ImageWidth | number = 384, fmt: 'webp' | 'avif' = 'webp'): string {27  const key = imageKey(url);28  return `/img/${key}.${fmt}?w=${width}&u=${b64url(url)}&s=${signImageUrl(url)}`;29}3031export interface ImageProps {32  src: string;33  srcSet: string;34}3536/** `src` + `srcSet` for a responsive `<img>`; `maxWidth` trims useless large variants for thumbnails. */37export function imageProps(url: string | null | undefined, opts: { maxWidth?: number } = {}): ImageProps | null {38  if (!url || !/^https?:\/\//i.test(url)) return null;39  const max = opts.maxWidth ?? 1200;40  const widths = IMAGE_WIDTHS.filter((w) => w <= Math.max(96, max * 2));41  const list = widths.length ? widths : [IMAGE_WIDTHS[0]];42  return {43    src: imgSrc(url, list[Math.min(list.length - 1, Math.max(0, list.findIndex((w) => w >= max)))] ?? 384),44    srcSet: list.map((w) => `${imgSrc(url, w)} ${w}w`).join(', '),45  };46}47