import { INGEST_PREFIX } from "~/lib/analytics";
import { analyticsConfig } from "./analytics";
const MAX_BODY_BYTES = 5 * 1024 * 1024;
const FORWARDED_REQUEST_HEADERS = ["content-type", "content-encoding", "accept", "accept-encoding", "user-agent"];
const DROPPED_RESPONSE_HEADERS = ["set-cookie", "access-control-allow-origin", "access-control-allow-credentials"];
/** PostHog serves the browser library's lazily loaded extensions from a separate assets host. */
export function ingestUpstream(host: string, path: string): string {
const assets = /^\/(static|array)\//.test(path);
const match = /^https:\/\/(us|eu)\.i\.posthog\.com$/.exec(host);
if (assets && match) return `https://${match[1]}-assets.i.posthog.com`;
return host;
}
/** Separators and dot segments, raw or percent-encoded in any case, that could re-point the upstream URL. */
const UNSAFE_PATH = /\/\/|\\|%2f|%5c|%2e|(^|\/)\.\.?(\/|$)/i;
/** The path after /ingest, or null when it is not a plain path PostHog could serve. */
export function ingestPath(rawPath: string): string | null {
const rest = rawPath.slice(INGEST_PREFIX.length) || "/";
if (!rest.startsWith("/") || UNSAFE_PATH.test(rest)) return null;
return rest;
}
/** Fixed upstream origin plus a vetted path; null unless the result is exactly the ingest or assets origin. */
export function ingestTarget(host: string, path: string, search: string): URL | null {
const origin = ingestUpstream(host, path);
const allowed = new Set([host, ingestUpstream(host, "/static/")]);
const target = new URL(origin);
target.pathname = path;
target.search = search;
return allowed.has(target.origin) && target.origin === origin ? target : null;
}
/**
* Same-origin reverse proxy for PostHog (/ingest/*), so the page never talks to a third party directly. Only
* the headers PostHog needs are forwarded: no cookies, credentials or client IP, and upstream cookies are
* dropped. Answers 404 when analytics is off.
*/