Skip to content
60 linesCodeBlameRaw

Pick any line to see why it is the way it is: the commit, the pull request and issue it came from, and what the agent was thinking.

Merge g1tusercontent.com: registry answers run nothing in a browser, the site's pages run only their own scripts, repository files and avatars on their own origin, raw files rate limited per address1/**
2 * A file of a repository as it is, for the Raw button, images on a file's
3 * page and pictures in a README: `/<owner>/<repo>/raw/<ref>/<path>`. Sends
4 * the viewer on to the file at the commit the ref names, on the usercontent
5 * origin (lib/usercontent.ts). A public repository's address is the same
6 * for everyone; a private one's carries a token for this file alone, made
7 * here for someone who can read the repository, good for an hour or two.
8 * Without USERCONTENT_KEY a private file is served from here instead,
9 * under the same policy.
10 */
11import { env } from "cloudflare:workers";
12
13import type { Route } from "./+types/raw";
14import { addresses } from "../../lib/addresses.server";
15import { repos } from "../../lib/services.server";
16import { getViewer } from "../../lib/session.server";
17import { MAX_RAW_BYTES, isCommit, rawHeaders, rawPath, signRaw } from "../../lib/usercontent";
18
19function refused(status: number, message: string): Response {
20 return new Response(`${message}\n`, {
21 status,
22 headers: { "content-type": "text/plain; charset=utf-8", "cache-control": "no-store", "x-content-type-options": "nosniff" },
23 });
24}
25
26export async function loader({ params, context }: Route.LoaderArgs) {
27 const viewer = getViewer(context);
28 const path = params["*"] ?? "";
29 if (!path) return refused(404, "Ask for /<owner>/<repo>/raw/<branch, tag or commit>/<path>.");
30 const named = { namespace: params.owner, name: params.repo };
31 const found = await repos.get(named, viewer).catch(() => null);
32 if (!found?.ok) return refused(404, "There is no such repository, or you cannot see it.");
33 const repo = found.value;
34 // The commit the ref names now, so the file's address never changes.
35 let commit = isCommit(params.ref) ? params.ref : null;
36 if (!commit) {
37 const log = await repos.log(named, viewer, params.ref, 1).catch(() => null);
38 commit = log?.ok ? (log.value[0]?.hash ?? null) : null;
39 }
40 if (!commit) return refused(404, `There is no branch, tag or commit named ${params.ref}.`);
41 const file = { owner: repo.namespace, repo: repo.name, ref: commit, path };
42 const target = `${addresses().usercontent}${rawPath(file)}`;
43 // Kept briefly when it followed a branch, which moves.
44 const cache = isCommit(params.ref) ? "private, max-age=86400" : "private, max-age=60";
45 if (!repo.isPrivate) return redirect(target, cache);
46 if (env.USERCONTENT_KEY) {
47 const token = await signRaw(env.USERCONTENT_KEY, file, repo.id);
48 return redirect(`${target}?token=${encodeURIComponent(token)}`, "private, max-age=600");
49 }
50 const raw = await repos.rawFile(repo.id, commit, path, MAX_RAW_BYTES).catch(() => null);
51 if (!raw) return refused(404, `There is no such file, or it is over ${MAX_RAW_BYTES / 1024 / 1024} MB. Clone the repository for it.`);
52 const bytes = Uint8Array.from(atob(raw.data), (c) => c.charCodeAt(0));
53 const headers = rawHeaders(path, bytes);
54 headers.set("cache-control", "private, max-age=60");
55 return new Response(bytes, { headers });
56}
57
58function redirect(location: string, cache: string): Response {
59 return new Response(null, { status: 302, headers: { location, "cache-control": cache } });
60}

This file's history is long; its oldest lines are credited to the oldest commit read.