218 lines · 8.8 KB
import { peekAuthToken, storeAuthToken } from "../auth-tokens";
import { first } from "../db";
import { accountDb } from "../scoped-db";
import { containersEnabled } from "./container-config";
import { containersAllowedFor } from "./container-meter";
import { credentialFromRequest, loadActiveUserById, sessionHandleIsLive, toViewer } from "../auth";
import { randomToken } from "../crypto";
import { notFoundError, unauthorized } from "../errors";
import { assertVisibleRevision } from "../git/reachable";
import { listRefs, resolveRevision } from "../git/refs";
import { directUpdateViolation, loadProtections, protectionFor } from "../protection";
import { hasPermission, loadRepoById, repoPermission } from "../repos";
import { credentialAllows, fineGrant, scopedRepoPermission } from "../token-scope";
import type { TokenGrant } from "../token-scope";
import type { ResolvedRevision } from "../git/refs";
import type { Permission, RepoRow, Viewer } from "~/lib/types";

export const EDITOR_TOKEN_PREFIX = "gitfor_edt";
const EDITOR_TOKEN_KIND = "editor-session";
const EDITOR_TOKEN_TTL_SECONDS = 60 * 60;
const UNLIMITED_ATTEMPTS = Number.MAX_SAFE_INTEGER;

/**
 * `patId` ties a session minted from a personal access token to that token, so revoking it ends the session;
 * `sessionHandle` ties a browser-minted session to the forge sign-in it came from, so signing out ends it.
 */
type SessionPayload = {
  repoId: string;
  ref: string;
  ceiling: Permission;
  canOpenPull: boolean;
  patId: string | null;
  sessionHandle: string | null;
};

export type MintGrant = {
  ceiling: Permission;
  canOpenPull: boolean;
  patId: string | null;
  sessionHandle?: string | null;