67 lines · 2.3 KB
import { env } from "cloudflare:workers";
import type { RepoRow } from "~/lib/types";
import { artifactsCall } from "./artifacts-call";

const TOKEN_TTL_SECONDS = 3600;
const TOKEN_CACHE_SECONDS = 3000;

export type TokenScope = "read" | "write";

export function tokenSecret(plaintext: string): string {
  return plaintext.split("?expires=")[0];
}

export function basicAuthHeader(secret: string): string {
  return `Basic ${btoa(`x:${secret}`)}`;
}

export function authenticatedRemote(remote: string, secret: string): string {
  const url = new URL(remote);
  url.username = "x";
  url.password = secret;
  return url.toString();
}

export async function openArtifactsRepo(artifactsName: string): Promise<ArtifactsRepo> {
  return artifactsCall("open repository", artifactsName, () => env.ARTIFACTS.get(artifactsName));
}

/** Mints (or reuses a cached) Artifacts token for git protocol access. */
export async function repoTokenSecret(repo: Pick<RepoRow, "artifacts_name">, scope: TokenScope): Promise<string> {
  const cacheKey = `artifacts-token:${repo.artifacts_name}:${scope}`;
  const cached = await env.KV.get(cacheKey);
  if (cached) return cached;
  const handle = await openArtifactsRepo(repo.artifacts_name);
  try {
    const token = await artifactsCall("mint an access token", repo.artifacts_name, () =>
      handle.createToken(scope, TOKEN_TTL_SECONDS),
    );
    const secret = tokenSecret(token.plaintext);
    await env.KV.put(cacheKey, secret, { expirationTtl: TOKEN_CACHE_SECONDS });