History

Randomize PostHog proxy path per build (#528)

Rhys Sullivan committed 6 months ago

Commit 0600b151 parent a7f2c663 files · +28 −7Browse files

Unified · Split

3 files
  1. apps/cloud/src/routes/__root.tsx +7 −1
  2. apps/cloud/src/start.ts +9 −5
  3. apps/cloud/vite.config.ts +12 −1
apps/cloud/src/routes/__root.tsx+7−1
@@ -26,8 +26,14 @@ if (typeof window !== "undefined" && import.meta.env.VITE_PUBLIC_SENTRY_DSN) { · 25 unmodified lines
26}26}
27 27
28if (typeof window !== "undefined" && import.meta.env.VITE_PUBLIC_POSTHOG_KEY) {28if (typeof window !== "undefined" && import.meta.env.VITE_PUBLIC_POSTHOG_KEY) {
29 const analyticsPath = (import.meta.env.VITE_PUBLIC_ANALYTICS_PATH ?? "a").replace(
30 /^\/+|\/+$/g,
31 "",
32 );
33
29 posthog.init(import.meta.env.VITE_PUBLIC_POSTHOG_KEY, {34 posthog.init(import.meta.env.VITE_PUBLIC_POSTHOG_KEY, {
30 api_host: import.meta.env.VITE_PUBLIC_POSTHOG_HOST ?? `${window.location.origin}/ingest`,35 api_host:
36 import.meta.env.VITE_PUBLIC_POSTHOG_HOST ?? `${window.location.origin}/api/${analyticsPath}`,
31 ui_host: "https://us.posthog.com",37 ui_host: "https://us.posthog.com",
32 defaults: "2025-05-24",38 defaults: "2025-05-24",
33 person_profiles: "identified_only",39 person_profiles: "identified_only",
apps/cloud/src/start.ts+9−5
@@ -106,28 +106,32 @@ const sentryTunnelMiddleware = createMiddleware({ type: "request" }).server( · 105 unmodified lines
106);106);
107 107
108// ---------------------------------------------------------------------------108// ---------------------------------------------------------------------------
109// PostHog reverse proxy — the browser SDK targets `/ingest/*` (configured in109// PostHog reverse proxy — the browser SDK targets a build-randomized
110// routes/__root.tsx) and we forward to PostHog's ingest + asset hosts. Keeps110// first-party path and we forward to PostHog's ingest + asset hosts. Keeps
111// events flowing past adblockers that match *.posthog.com. See111// events flowing past adblockers that match *.posthog.com. See
112// https://posthog.com/docs/advanced/proxy/cloudflare112// https://posthog.com/docs/advanced/proxy/cloudflare
113// ---------------------------------------------------------------------------113// ---------------------------------------------------------------------------
114 114
115const POSTHOG_INGEST_HOST = "us.i.posthog.com";115const POSTHOG_INGEST_HOST = "us.i.posthog.com";
116const POSTHOG_ASSETS_HOST = "us-assets.i.posthog.com";116const POSTHOG_ASSETS_HOST = "us-assets.i.posthog.com";
117const POSTHOG_PROXY_PATH = `/api/${(import.meta.env.VITE_PUBLIC_ANALYTICS_PATH ?? "a").replace(
118 /^\/+|\/+$/g,
119 "",
120)}`;
117 121
118const posthogProxyMiddleware = createMiddleware({ type: "request" }).server(122const posthogProxyMiddleware = createMiddleware({ type: "request" }).server(
119 ({ pathname, request, next }) => {123 ({ pathname, request, next }) => {
120 if (pathname !== "/ingest" && !pathname.startsWith("/ingest/")) {124 if (pathname !== POSTHOG_PROXY_PATH && !pathname.startsWith(`${POSTHOG_PROXY_PATH}/`)) {
121 return next();125 return next();
122 }126 }
123 127
124 const url = new URL(request.url);128 const url = new URL(request.url);
125 url.hostname = pathname.startsWith("/ingest/static/")129 url.hostname = pathname.startsWith(`${POSTHOG_PROXY_PATH}/static/`)
126 ? POSTHOG_ASSETS_HOST130 ? POSTHOG_ASSETS_HOST
127 : POSTHOG_INGEST_HOST;131 : POSTHOG_INGEST_HOST;
128 url.protocol = "https:";132 url.protocol = "https:";
129 url.port = "";133 url.port = "";
130 url.pathname = pathname.replace(/^\/ingest/, "") || "/";134 url.pathname = pathname.slice(POSTHOG_PROXY_PATH.length) || "/";
131 135
132 const upstream = new Request(url, request);136 const upstream = new Request(url, request);
133 upstream.headers.delete("cookie");137 upstream.headers.delete("cookie");
apps/cloud/vite.config.ts+12−1
@@ -1,3 +1,4 @@
1import { randomUUID } from "node:crypto";
1import { fileURLToPath } from "node:url";2import { fileURLToPath } from "node:url";
2import { defineConfig, loadEnv, type Plugin } from "vite";3import { defineConfig, loadEnv, type Plugin } from "vite";
3import { cloudflare } from "@cloudflare/vite-plugin";4import { cloudflare } from "@cloudflare/vite-plugin";
@@ -44,9 +45,19 @@ const loadWranglerPublicVars = () => { · 40 unmodified lines
44 );45 );
45};46};
46 47
48let generatedAnalyticsPath: string | undefined;
49const getGeneratedAnalyticsPath = () => {
50 generatedAnalyticsPath ??= randomUUID().slice(0, 8);
51 return generatedAnalyticsPath;
52};
53
47export default defineConfig(({ mode }) => {54export default defineConfig(({ mode }) => {
48 const env = loadEnv(mode, process.cwd(), "");55 const env = loadEnv(mode, process.cwd(), "");
49 const publicEnv = { ...loadWranglerPublicVars(), ...env };56 const publicEnv = {
57 ...loadWranglerPublicVars(),
58 VITE_PUBLIC_ANALYTICS_PATH: getGeneratedAnalyticsPath(),
59 ...env,
60 };
50 61
51 return {62 return {
52 define: Object.fromEntries(63 define: Object.fromEntries(