353 lines · 16.3 KB
import { parseLanguages } from "~/lib/languages";
import { parseTopics } from "~/lib/topics";
import { isTakenDown } from "~/lib/account-disable";
import { all, chunks, first, placeholders } from "./db";
import { isScratchRepo } from "./sites/config";
import { HttpError, forbidden, notFoundError } from "./errors";
import type { Permission, RepoRow, RepoSummary, Viewer } from "~/lib/types";

const PERMISSION_RANK: Record<Permission, number> = { none: 0, read: 1, write: 2, admin: 3 };

/** What a plain org member gets on every repository the org owns; owners always get `admin`. */
export const ORG_DEFAULT_PERMISSIONS = ["none", "read", "write"] as const;
export type OrgDefaultPermission = (typeof ORG_DEFAULT_PERMISSIONS)[number];

function orgDefaultPermission(value: string | null | undefined): OrgDefaultPermission {
  return value === "none" || value === "write" ? value : "read";
}

/**
 * SQL predicate: the user `userExpr` can read the repo aliased `repoAlias` (public, owner, collaborator, org
 * owner, or org member when the org's default permission grants at least read). Site admins are not covered;
 * callers short-circuit them.
 */
export function repoReadableSql(repoAlias: string, userExpr: string): string {
  return `(${repoAlias}.visibility = 'public' OR ${repoAlias}.owner_id = ${userExpr}
  OR EXISTS (SELECT 1 FROM collaborators c_ WHERE c_.repo_id = ${repoAlias}.id AND c_.user_id = ${userExpr})
  OR EXISTS (SELECT 1 FROM org_members m_ JOIN accounts o_ ON o_.id = m_.org_id
    WHERE m_.org_id = ${repoAlias}.owner_id AND m_.user_id = ${userExpr}
      AND (m_.role = 'owner' OR o_.org_default_permission != 'none')))`;
}

/**
 * SQL predicate for inbox rows (`alias.repo_id`, `alias.user_id`): account-level rows, or rows on a repository
 * the recipient can still read (site admins read everything). Reads filter on it so a revocation that has not
 * been purged yet never leaks private titles (authz-P7).
 */
export function inboxReadableSql(alias: string): string {
  return `(${alias}.repo_id IS NULL
  OR EXISTS (SELECT 1 FROM repos ir_ WHERE ir_.id = ${alias}.repo_id AND ir_.hidden_at IS NULL AND ${repoReadableSql("ir_", `${alias}.user_id`)})
  OR EXISTS (SELECT 1 FROM users iu_ WHERE iu_.account_id = ${alias}.user_id AND iu_.is_admin = 1))`;