164 lines · 7.3 KB
import { env } from "cloudflare:workers";
import { viewerFromRequest, viewerFromSessionCookie } from "./auth";
import { loadRepo, loadRepoById, repoPermission } from "./repos";
import { first, run } from "./db";
import { randomId } from "./crypto";
import { limitBrowse, limitWrite } from "./limits";
import { HttpError } from "./errors";
import type { Viewer } from "~/lib/types";

const UPLOAD_PATH = /^\/([^/]+)\/([^/]+)\/attachments$/;
const SERVE_PATH = /^\/attachments\/([a-z0-9]+)\/([^/]+)$/;
const MB = 1024 * 1024;
const MAX_IMAGE_BYTES = 10 * MB;
const MAX_FILE_BYTES = 25 * MB;
const OWNER_QUOTA_BYTES = 1024 * MB;
const UPLOADER_QUOTA_BYTES = 250 * MB;
const WIDTH_BUCKETS = [320, 640, 1280, 2560];
const MAX_IMAGE_WIDTH = WIDTH_BUCKETS[WIDTH_BUCKETS.length - 1];
const HTTP_FORBIDDEN = 403;
const HTTP_TOO_LARGE = 413;
const HTTP_UNSUPPORTED = 415;
const TRANSFORMABLE_IMAGES = new Set(["image/png", "image/jpeg", "image/webp", "image/avif"]);
const ALLOWED_TYPES = new Set([
  ...TRANSFORMABLE_IMAGES,
  "image/gif",
  "video/mp4",
  "video/webm",
  "application/pdf",
  "application/zip",
  "application/gzip",
  "application/json",
  "text/plain",
  "text/csv",
  "text/markdown",
]);

async function viewerFor(request: Request): Promise<Viewer | null> {
  return (await viewerFromSessionCookie(request)) ?? (await viewerFromRequest(request));
}