38 lines · 1.4 KB
export type LfsPointer = { oid: string; size: number };

/** Spec-compliant pointers are tiny; anything larger is real content and is never parsed. */
export const MAX_POINTER_BYTES = 1024;

const POINTER_VERSION = "version https://git-lfs.github.com/spec/v1";
const LEGACY_VERSION = "version https://hawser.github.com/spec/v1";
const OID_LINE = /^oid sha256:([0-9a-f]{64})$/;
const SIZE_LINE = /^size (\d{1,16})$/;
const OID_PATTERN = /^[0-9a-f]{64}$/;
const decoder = new TextDecoder("utf-8", { fatal: true });

export function isValidOid(oid: string): boolean {
  return OID_PATTERN.test(oid);
}

export function parseLfsPointer(bytes: Uint8Array): LfsPointer | null {
  if (bytes.byteLength === 0 || bytes.byteLength > MAX_POINTER_BYTES) return null;
  let text: string;
  try {
    text = decoder.decode(bytes);
  } catch {
    return null;
  }
  const lines = text.replace(/\r\n/g, "\n").split("\n").filter(Boolean);
  if (lines[0] !== POINTER_VERSION && lines[0] !== LEGACY_VERSION) return null;
  let oid: string | null = null;
  let size: number | null = null;
  for (const line of lines.slice(1)) {
    const oidMatch = OID_LINE.exec(line);
    if (oidMatch) oid = oidMatch[1];
    const sizeMatch = SIZE_LINE.exec(line);
    if (sizeMatch) size = Number(sizeMatch[1]);
  }
  if (oid === null || size === null || !Number.isSafeInteger(size)) return null;
  return { oid, size };
}