244 lines · 10.7 KB
import { sameOriginReport } from "./report-origin";
import { env } from "cloudflare:workers";
import { all, first, run } from "../db";
import { sha256Hex } from "../crypto";
import { HttpError, badRequest } from "../errors";
import { enforceRateLimit, requestIp } from "../limits";
import { extractArtifact, storeFile } from "./collect";
import { manifestKey, metaKey, publishMeta, SCRATCH_LIMITS, slotKey } from "./config";
import { assertLabelFree, loadSiteById, unpublishSite } from "./deploy";
import { claimedLabel } from "./naming";
import { onScratchClaimed } from "./metering";
import { CLAIM_PREFIX, deployUpload, reserveScratch, scratchResult } from "./scratch-core";
import {
  assertScratchRepoTransferable,
  createScratchRepo,
  sweepOrphanScratchRepos,
  transferScratchRepo,
} from "./scratch-git";
import type { CollectedFiles } from "./collect";
import type { ScratchResult } from "./scratch-core";
import { plain } from "./static";
import { guessAbuseCategory, recordAbuseReport } from "../abuse";
import type { SiteMeta, SiteRow } from "./config";
import type { Viewer } from "~/lib/types";

const HTTP_TOO_LARGE = 413;
const MIB = 1024 * 1024;
const SWEEP_BATCH = 50;

async function readCapped(
  request: Request,
  limit: number = SCRATCH_LIMITS.maxUploadBytes,
  allowEmpty = false,
): Promise<Uint8Array<ArrayBuffer>> {
  const tooLarge = () => new HttpError(HTTP_TOO_LARGE, `Upload exceeds ${Math.round(limit / MIB)} MiB`);
  const declared = Number(request.headers.get("content-length") ?? "0");
  if (declared > limit) throw tooLarge();
  if (!request.body) {
    if (allowEmpty) return new Uint8Array(0);
    throw badRequest("Send a .tar.gz archive as the request body");