129 lines · 5.5 KB
import { env } from "cloudflare:workers";
import { viewerFromSessionCookie } from "../auth";
import { first } from "../db";
import { randomToken, sha256Hex } from "../crypto";
import { HttpError } from "../errors";
import { limitWrite } from "../limits";
import { hasPermission, loadRepoById, repoPermission } from "../repos";
import { codeKey, labelUrl, siteOrigin } from "./config";
import { CALLBACK_PATH } from "./access";
import { resolveSiteHost } from "./dispatch";
import { claimScratchSite } from "./scratch";
import { html } from "./static";
import { claimPage } from "./claim-page";
import type { SiteMeta } from "./config";
import type { Viewer } from "~/lib/types";

const CODE_TTL_SECONDS = 60;

function page(status: number, title: string, body: string): Response {
  return html(
    status,
    `<!doctype html><meta name="viewport" content="width=device-width"><title>${title}</title>
<body style="font-family:system-ui;max-width:30rem;margin:4rem auto;line-height:1.5"><h1 style="font-size:1.25rem">${title}</h1>${body}</body>`,
  );
}

function escapeHtml(value: string): string {
  return value.replace(/[&<>"']/g, (char) => `&#${char.charCodeAt(0)};`);
}

function signInFirst(): Response {
  return page(
    401,
    "Sign in to continue",
    `<p>Sign in to ${escapeHtml(env.FORGE_NAME)} in this browser, then return to the site and try again.</p><p><a href="/login">Sign in</a></p>`,
  );
}

async function allowed(site: SiteMeta, viewer: Viewer): Promise<boolean> {
  if (!site.repoId) return site.ownerId === viewer.id;