Skip to content

Where people and agents ship software together. The open-source git platform for the whole job: issues, agents, checks and deploys to the edge.

g1t.sh
50 linesCodeBlameRaw

Pick any line to see why it is the way it is: the commit, the pull request and issue it came from, and what the agent was thinking.

Git storage hardened, pages in tens of milliseconds, honest security alerts, and costs reconciled daily1/**
2 * An avatar as it arrives from a form: read, checked and turned into the
3 * base64 the identity service takes. Identity checks it again, by its
4 * bytes, and is the one that decides; this only turns away what is
5 * plainly wrong before sending a megabyte across.
6 */
7
8/** As `MAX_AVATAR_BYTES` in the contracts: kept here so tests run without them. */
9export const MAX_AVATAR_BYTES = 1024 * 1024;
10
11/** What an `<input type="file">` offers to pick. SVG is left out on purpose. */
12export const AVATAR_ACCEPT = "image/png,image/jpeg,image/webp,image/gif";
13
14/** The type an image's first bytes show it to be, or null. As identity's `sniff`. */
15export function sniffImage(bytes: Uint8Array): string | null {
16 const starts = (...prefix: number[]) => prefix.every((byte, i) => bytes[i] === byte);
17 const ascii = (at: number, text: string) => [...text].every((char, i) => bytes[at + i] === char.charCodeAt(0));
18 if (starts(0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a)) return "image/png";
19 if (starts(0xff, 0xd8, 0xff)) return "image/jpeg";
20 if (ascii(0, "GIF87a") || ascii(0, "GIF89a")) return "image/gif";
21 if (bytes.length >= 12 && ascii(0, "RIFF") && ascii(8, "WEBP")) return "image/webp";
22 return null;
23}
24
25/** Bytes as base64, in chunks so a large file does not overflow the stack. */
26export function toBase64(bytes: Uint8Array): string {
27 let binary = "";
28 for (let i = 0; i < bytes.length; i += 0x8000) {
29 binary += String.fromCharCode(...bytes.subarray(i, i + 0x8000));
30 }
31 return btoa(binary);
32}
33
34export type AvatarUpload = { image: string } | { error: string };
35
36/** Reads the file in `field` of a submitted form. */
37export async function readAvatarUpload(form: FormData, field = "avatar"): Promise<AvatarUpload> {
38 const file = form.get(field);
39 if (!file || typeof file === "string" || file.size === 0) {
40 return { error: "Choose an image to upload." };
41 }
42 if (file.size > MAX_AVATAR_BYTES) {
43 return { error: "Use an image of at most 1 MB." };
44 }
45 const bytes = new Uint8Array(await file.arrayBuffer());
46 if (!sniffImage(bytes)) {
47 return { error: "Use a PNG, JPEG, WebP or GIF image." };
48 }
49 return { image: toBase64(bytes) };
50}

This file's history is long; its oldest lines are credited to the oldest commit read.