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(