feat(sharing): serve a configured public resume at root (#3470)

This commit is contained in:
Amruth Pillai
2026-09-05 19:42:44 -07:00
committed by GitHub
parent 870388192e
commit 744eaa902e
24 changed files with 768 additions and 26 deletions
@@ -0,0 +1,97 @@
import { describe, expect, it, vi } from "vitest";
import { ORPCError } from "@orpc/server";
import { defaultResumeData } from "@reactive-resume/schema/resume/default";
import { getRootResume } from "./root";
const fixture = () => ({
config: { rootResumeId: "root-id", appUrl: "https://resume.example/base?ignored=yes" },
findTarget: vi.fn(async (_id: string) => ({ username: "owner", slug: "current-slug", isPublic: true })),
getBySlug: vi.fn(async (_input: unknown) => ({
id: "root-id",
name: "Resume",
slug: "current-slug",
data: defaultResumeData,
tags: [],
isPublic: true,
isLocked: false,
showDownloadButtons: false,
hasPassword: false,
})),
});
const request = { requestHeaders: new Headers({ host: "attacker.example", "x-forwarded-host": "attacker.example" }) };
describe("configured root public resume", () => {
it.each([undefined, "", " "])("disables root mode for %s without a lookup", async (rootResumeId) => {
const deps = fixture();
const result = await getRootResume(request, { ...deps, config: { ...deps.config, rootResumeId } });
expect(result).toEqual({ status: "disabled" });
expect(deps.findTarget).not.toHaveBeenCalled();
expect(deps.getBySlug).not.toHaveBeenCalled();
});
it.each([null, { username: "secret-owner", slug: "secret-slug", isPublic: false }])(
"does not disclose an unavailable target to its owner",
async (target) => {
const deps = fixture();
const result = await getRootResume(
{ ...request, currentUserId: "owner-id" },
{ ...deps, findTarget: async () => target },
);
expect(result).toEqual({ status: "unavailable", canonicalUrl: "https://resume.example/" });
expect(deps.getBySlug).not.toHaveBeenCalled();
},
);
it("resolves only configured ID and delegates once with public-only enforcement", async () => {
const deps = fixture();
const result = await getRootResume({ ...request, currentUserId: "owner-id" }, deps);
expect(result).toMatchObject({
status: "public",
username: "owner",
slug: "current-slug",
canonicalUrl: "https://resume.example/",
resume: { showDownloadButtons: false, hasPassword: false },
});
expect(deps.findTarget).toHaveBeenCalledExactlyOnceWith("root-id");
expect(deps.getBySlug).toHaveBeenCalledExactlyOnceWith({
...request,
currentUserId: "owner-id",
username: "owner",
slug: "current-slug",
requirePublic: true,
expectedResumeId: "root-id",
});
});
it("uses the renamed slug on the next request", async () => {
const deps = fixture();
deps.findTarget.mockResolvedValue({ username: "renamed-owner", slug: "renamed-slug", isPublic: true });
expect(await getRootResume(request, deps)).toMatchObject({ username: "renamed-owner", slug: "renamed-slug" });
});
it("keeps a privacy change during the final lookup unavailable", async () => {
const deps = fixture();
deps.getBySlug.mockRejectedValue(new ORPCError("NOT_FOUND"));
expect(await getRootResume(request, deps)).toEqual({
status: "unavailable",
canonicalUrl: "https://resume.example/",
});
});
it("preserves the existing password challenge identity", async () => {
const deps = fixture();
deps.getBySlug.mockRejectedValue(
new ORPCError("NEED_PASSWORD", { status: 401, data: { username: "owner", slug: "current-slug" } }),
);
await expect(getRootResume(request, deps)).rejects.toMatchObject({
code: "NEED_PASSWORD",
data: { username: "owner", slug: "current-slug" },
});
});
it("does not hide infrastructure failures as missing resumes", async () => {
const deps = fixture();
deps.getBySlug.mockRejectedValue(new Error("database unavailable"));
await expect(getRootResume(request, deps)).rejects.toThrow("database unavailable");
});
});
+57
View File
@@ -0,0 +1,57 @@
import type { resumeService } from "./service";
import { ORPCError } from "@orpc/server";
type RootRequest = { requestHeaders: Headers; currentUserId?: string };
type RootDependencies = {
config: { rootResumeId?: string | undefined; appUrl: string };
findTarget(id: string): Promise<{ username: string; slug: string; isPublic: boolean } | null>;
getBySlug: typeof resumeService.getBySlug;
};
const getDependencies = async (): Promise<RootDependencies> => {
const [{ env }, { db }, schema, { eq }, { resumeService }] = await Promise.all([
import("@reactive-resume/env/server"),
import("@reactive-resume/db/client"),
import("@reactive-resume/db/schema"),
import("drizzle-orm"),
import("./service"),
]);
return {
config: { rootResumeId: env.ROOT_RESUME_ID, appUrl: env.APP_URL },
findTarget: async (id) => {
const [target] = await db
.select({ username: schema.user.username, slug: schema.resume.slug, isPublic: schema.resume.isPublic })
.from(schema.resume)
.innerJoin(schema.user, eq(schema.resume.userId, schema.user.id))
.where(eq(schema.resume.id, id));
return target ?? null;
},
getBySlug: resumeService.getBySlug,
};
};
/** Instance configuration is the sole authority; callers cannot choose a host or target. */
export async function getRootResume(input: RootRequest, dependencies?: RootDependencies) {
const { config, findTarget, getBySlug } = dependencies ?? (await getDependencies());
const id = config.rootResumeId?.trim();
if (!id) return { status: "disabled" as const };
const canonicalUrl = new URL("/", config.appUrl).href;
const unavailable = { status: "unavailable" as const, canonicalUrl };
const target = await findTarget(id);
if (!target?.isPublic) return unavailable;
try {
const resume = await getBySlug({
...input,
username: target.username,
slug: target.slug,
requirePublic: true,
expectedResumeId: id,
});
return { status: "public" as const, canonicalUrl, username: target.username, slug: target.slug, resume };
} catch (error) {
if (error instanceof ORPCError && error.code === "NOT_FOUND") return unavailable;
throw error;
}
}
@@ -1,11 +1,19 @@
import { publicProcedure } from "../../context";
import { crudRouter } from "./crud";
import { updatesRouter } from "./event-router";
import { getRootResume } from "./root";
import { sharingRouter } from "./sharing";
import { resumeStatisticsRouter } from "./statistics";
import { tagsRouter } from "./tags";
import { versionsRouter } from "./versions";
export const resumeRouter = {
getRoot: publicProcedure.handler(({ context }) =>
getRootResume({
requestHeaders: context.reqHeaders,
...(context.user?.id ? { currentUserId: context.user.id } : {}),
}),
),
tags: tagsRouter,
statistics: resumeStatisticsRouter,
updates: updatesRouter,
@@ -1096,3 +1096,47 @@ describe("statistics.recordDownload", () => {
expect(values).toHaveBeenCalledTimes(2);
});
});
describe("root public-only lookup", () => {
it("rejects a private target even for its owner after identity resolution", async () => {
const row = {
...createResumeRow(defaultResumeData),
userId: "u1",
isPublic: false,
hasPassword: false,
passwordHash: null,
};
dbMock.select.mockReturnValue({ from: () => ({ innerJoin: () => ({ where: async () => [row] }) }) });
await expect(
resumeService.getBySlug({
username: "owner",
slug: "resume",
requestHeaders: new Headers(),
currentUserId: "u1",
requirePublic: true,
}),
).rejects.toMatchObject({ code: "NOT_FOUND" });
});
});
it("rejects a different resume reusing the resolved root slug", async () => {
const row = {
...createResumeRow(defaultResumeData),
id: "replacement-id",
userId: "u1",
isPublic: true,
hasPassword: false,
passwordHash: null,
};
dbMock.select.mockReturnValue({ from: () => ({ innerJoin: () => ({ where: async () => [row] }) }) });
await expect(
resumeService.getBySlug({
username: "owner",
slug: "resume",
requestHeaders: new Headers(),
currentUserId: "u1",
requirePublic: true,
expectedResumeId: "configured-id",
}),
).rejects.toMatchObject({ code: "NOT_FOUND" });
});
+14 -2
View File
@@ -512,7 +512,14 @@ export const resumeService = {
return resume;
},
getBySlug: async (input: { username: string; slug: string; requestHeaders: Headers; currentUserId?: string }) => {
getBySlug: async (input: {
username: string;
slug: string;
requestHeaders: Headers;
currentUserId?: string;
requirePublic?: boolean;
expectedResumeId?: string;
}) => {
const [resume] = await db
.select({
id: schema.resume.id,
@@ -531,7 +538,12 @@ export const resumeService = {
.innerJoin(schema.user, eq(schema.resume.userId, schema.user.id))
.where(and(eq(schema.resume.slug, input.slug), eq(schema.user.username, input.username)));
if (!resume) throw new ORPCError("NOT_FOUND");
if (
!resume ||
(input.requirePublic && !resume.isPublic) ||
(input.expectedResumeId && resume.id !== input.expectedResumeId)
)
throw new ORPCError("NOT_FOUND");
const viewer = input.currentUserId ? { id: input.currentUserId } : null;
assertCanView(resume, viewer);