From 683944ebe219f20d202b552a5bd0e095cf2aa3b7 Mon Sep 17 00:00:00 2001 From: khannurien Date: Fri, 9 Oct 2026 22:04:35 +0000 Subject: [PATCH] =?UTF-8?q?v4:=20a=20remote=20user's=20pages=20get=20their?= =?UTF-8?q?=20link=20previews=20and=20redirects=20=E2=80=94=20the=20Open?= =?UTF-8?q?=20Graph=20middleware=20passed=20on=20every=20path=20with=20a?= =?UTF-8?q?=20dot=20in=20it,=20taking=20it=20for=20a=20file's,=20and=20the?= =?UTF-8?q?=20handle=20of=20a=20user=20from=20a=20real=20host=20has=20dots?= =?UTF-8?q?=20(/@bob@music.example),=20so=20their=20profile,=20dumps=20and?= =?UTF-8?q?=20playlists=20had=20no=20tags,=20and=20a=20former=20name=20or?= =?UTF-8?q?=20another=20case=20of=20theirs=20no=20301.=20Only=20the=20dev?= =?UTF-8?q?=20instances'=20localhost:8000=20escaped=20it.=20parsePagePath?= =?UTF-8?q?=20already=20passes=20on=20any=20path=20that=20doesn't=20start?= =?UTF-8?q?=20with=20@,=20which=20no=20file's=20does,=20so=20the=20dot=20c?= =?UTF-8?q?heck=20is=20gone.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Claude Opus 5.5 --- api/middleware/og.ts | 6 +++--- api/test/middleware/og.test.ts | 10 ++++++++++ 2 files changed, 13 insertions(+), 3 deletions(-) diff --git a/api/middleware/og.ts b/api/middleware/og.ts index e0c2365a..21069f41 100644 --- a/api/middleware/og.ts +++ b/api/middleware/og.ts @@ -114,9 +114,9 @@ export async function ogMiddleware( ): Promise { const { pathname } = ctx.request.url; - if (pathname.startsWith("/api/") || pathname.includes(".")) { - return await next(); - } + // A file's path never starts with `@`, so parsePagePath passes it on, while + // a remote user's has dots in it: `/@bob@music.example`. + if (pathname.startsWith("/api/")) return await next(); const page = parsePagePath(pathname); if (!page || (page.kind === "dump" && page.edit)) return await next(); diff --git a/api/test/middleware/og.test.ts b/api/test/middleware/og.test.ts index afffb623..0f623144 100644 --- a/api/test/middleware/og.test.ts +++ b/api/test/middleware/og.test.ts @@ -151,6 +151,16 @@ test("ogMiddleware: a former slug, a former name or another case gets a 301", as assertEquals(res.status, 301, from); assertEquals(res.headers.get("location"), `${BASE_URL}${to}`, from); } + // A remote user's path has dots in it, as a file's does. + const remote = await createUser({ username: "bob@music.example" }); + const remoteDump = insertDump({ userId: remote.id, title: "Far" }); + assertStringIncludes( + (await handle(ogApp(), remoteDump.path)).text, + ``, + ); + const { res } = await handle(ogApp(), "/@BOB@music.example/dumps/far"); + assertEquals(res.status, 301); + assertEquals(res.headers.get("location"), `${BASE_URL}${remoteDump.path}`); // A private dump's former slug tells nothing. const secret = insertDump({ userId: user.id, title: "S", isPrivate: true }); db.prepare(