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
256 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.

Put the stylesheet at the top of the head, before React Router's preloads1import assert from "node:assert/strict";
2import { beforeEach, test } from "node:test";
3
4import {
5 type AccessSettings,
6 authorize,
7 clearKeyCache,
8 isSameOrigin,
9 isStaff,
sudo: Access service tokens listed in STAFF_SERVICE_TOKENS are staff, recorded as <name>@service.g1t.sh10 parseServiceTokens,
Put the stylesheet at the top of the head, before React Router's preloads11 parseStaff,
12 readSettings,
13 verifyAccessJwt,
14} from "./access.ts";
15
16const TEAM = "g1t.cloudflareaccess.com";
17const AUD = "a".repeat(64);
sudo: Access service tokens listed in STAFF_SERVICE_TOKENS are staff, recorded as <name>@service.g1t.sh18const CLIENT = "434297ede60761875e84742d0486cf27.access";
19const SETTINGS: AccessSettings = { teamDomain: TEAM, aud: AUD, staff: ["owner@g1t.sh"], services: new Map([[CLIENT, "claude"]]) };
Put the stylesheet at the top of the head, before React Router's preloads20const NOW = Date.UTC(2026, 9, 4, 12, 0, 0);
21const NOW_SECONDS = Math.floor(NOW / 1000);
22const RSA = { name: "RSASSA-PKCS1-v1_5", hash: "SHA-256" } as const;
23
24async function rsaKey() {
25 return crypto.subtle.generateKey(
26 { ...RSA, modulusLength: 2048, publicExponent: new Uint8Array([1, 0, 1]) },
27 true,
28 ["sign", "verify"],
29 );
30}
31
32const signing = await rsaKey();
33const stranger = await rsaKey();
34const publicJwk = { ...(await crypto.subtle.exportKey("jwk", signing.publicKey)), kid: "key-1", alg: "RS256", use: "sig" };
35
36function b64url(bytes: Uint8Array | string): string {
37 const raw = typeof bytes === "string" ? new TextEncoder().encode(bytes) : bytes;
38 let binary = "";
39 for (const byte of raw) binary += String.fromCharCode(byte);
40 return btoa(binary).replace(/\+/g, "-").replace(/\//g, "_").replace(/=+$/, "");
41}
42
43async function sign(
44 claims: Record<string, unknown>,
45 { key = signing.privateKey, kid = "key-1", alg = "RS256" }: { key?: CryptoKey; kid?: string; alg?: string } = {},
46): Promise<string> {
47 const body = `${b64url(JSON.stringify({ alg, kid, typ: "JWT" }))}.${b64url(JSON.stringify(claims))}`;
48 const signature = new Uint8Array(await crypto.subtle.sign(RSA, key, new TextEncoder().encode(body)));
49 return `${body}.${b64url(signature)}`;
50}
51
52function claims(overrides: Record<string, unknown> = {}): Record<string, unknown> {
53 return {
54 iss: `https://${TEAM}`,
55 aud: [AUD],
56 email: "owner@g1t.sh",
57 sub: "user-1",
58 iat: NOW_SECONDS - 60,
59 nbf: NOW_SECONDS - 60,
60 exp: NOW_SECONDS + 3600,
61 ...overrides,
62 };
63}
64
65let fetches: string[] = [];
66async function fetcher(url: string): Promise<Response> {
67 fetches.push(url);
68 return Response.json({ keys: [publicJwk], public_cert: { kid: "key-1", cert: "" } });
69}
70
71function request(token?: string): Request {
72 return new Request("https://sudo.g1t.sh/", {
73 headers: token ? { "cf-access-jwt-assertion": token } : {},
74 });
75}
76
77beforeEach(() => {
78 clearKeyCache();
79 fetches = [];
80});
81
82test("a valid token from staff is let in, by its email", async () => {
83 const result = await authorize(request(await sign(claims())), SETTINGS, { fetcher, now: NOW });
84 assert.deepEqual(result, { ok: true, email: "owner@g1t.sh" });
85 assert.deepEqual(fetches, [`https://${TEAM}/cdn-cgi/access/certs`]);
86});
87
88test("an audience given as a string is accepted too", async () => {
89 const result = await verifyAccessJwt(await sign(claims({ aud: AUD })), SETTINGS, { fetcher, now: NOW });
90 assert.equal(result.ok, true);
91});
92
93test("a token for another Access application is refused", async () => {
94 const result = await verifyAccessJwt(await sign(claims({ aud: ["b".repeat(64)] })), SETTINGS, { fetcher, now: NOW });
95 assert.deepEqual(result, { ok: false, reason: "wrong audience" });
96});
97
98test("a token from another team is refused", async () => {
99 const result = await verifyAccessJwt(
100 await sign(claims({ iss: "https://evil.cloudflareaccess.com" })),
101 SETTINGS,
102 { fetcher, now: NOW },
103 );
104 assert.deepEqual(result, { ok: false, reason: "wrong issuer" });
105});
106
107test("an expired token is refused", async () => {
108 const result = await verifyAccessJwt(await sign(claims({ exp: NOW_SECONDS - 3600 })), SETTINGS, { fetcher, now: NOW });
109 assert.deepEqual(result, { ok: false, reason: "expired" });
110});
111
112test("a token without an expiry is refused", async () => {
113 const result = await verifyAccessJwt(await sign(claims({ exp: undefined })), SETTINGS, { fetcher, now: NOW });
114 assert.deepEqual(result, { ok: false, reason: "no expiry" });
115});
116
117test("a token not valid yet is refused", async () => {
118 const result = await verifyAccessJwt(await sign(claims({ nbf: NOW_SECONDS + 3600 })), SETTINGS, { fetcher, now: NOW });
119 assert.deepEqual(result, { ok: false, reason: "not yet valid" });
120});
121
122test("a token signed by another key under a known key id is refused", async () => {
123 const result = await verifyAccessJwt(await sign(claims(), { key: stranger.privateKey }), SETTINGS, { fetcher, now: NOW });
124 assert.deepEqual(result, { ok: false, reason: "bad signature" });
125});
126
127test("a token whose claims were changed after signing is refused", async () => {
128 const token = await sign(claims({ email: "intern@g1t.sh" }));
129 const [header, , signature] = token.split(".");
130 const forged = `${header}.${b64url(JSON.stringify(claims()))}.${signature}`;
131 const result = await authorize(request(forged), SETTINGS, { fetcher, now: NOW });
132 assert.deepEqual(result, { ok: false, reason: "bad signature" });
133});
134
135test("a token signed by a key the team does not publish is refused", async () => {
136 const result = await verifyAccessJwt(await sign(claims(), { kid: "key-9" }), SETTINGS, { fetcher, now: NOW });
137 assert.deepEqual(result, { ok: false, reason: "unknown signing key" });
138});
139
140test("alg none and HS256 are refused before any key is fetched", async () => {
141 for (const alg of ["none", "HS256"]) {
142 const result = await verifyAccessJwt(await sign(claims(), { alg }), SETTINGS, { fetcher, now: NOW });
143 assert.deepEqual(result, { ok: false, reason: "unexpected algorithm" });
144 }
145 assert.deepEqual(fetches, []);
146});
147
148test("a valid token whose email is not staff is refused", async () => {
149 const result = await authorize(request(await sign(claims({ email: "someone@example.com" }))), SETTINGS, {
150 fetcher,
151 now: NOW,
152 });
153 assert.deepEqual(result, { ok: false, reason: "not staff", email: "someone@example.com" });
154});
155
sudo: Access service tokens listed in STAFF_SERVICE_TOKENS are staff, recorded as <name>@service.g1t.sh156test("a token with neither an email nor a client id is refused", async () => {
Put the stylesheet at the top of the head, before React Router's preloads157 const result = await authorize(request(await sign(claims({ email: undefined }))), SETTINGS, { fetcher, now: NOW });
158 assert.deepEqual(result, { ok: false, reason: "token has no email" });
159});
160
sudo: Access service tokens listed in STAFF_SERVICE_TOKENS are staff, recorded as <name>@service.g1t.sh161test("a listed service token is let in as its name at service.g1t.sh", async () => {
162 const token = await sign(claims({ email: undefined, sub: "", common_name: CLIENT }));
163 const result = await authorize(request(token), SETTINGS, { fetcher, now: NOW });
164 assert.deepEqual(result, { ok: true, email: "claude@service.g1t.sh" });
165});
166
167test("a service token not listed is refused", async () => {
168 const token = await sign(claims({ email: undefined, common_name: "ffffffffffffffffffffffffffffffff.access" }));
169 const result = await authorize(request(token), SETTINGS, { fetcher, now: NOW });
170 assert.deepEqual(result, { ok: false, reason: "service token not staff" });
171});
172
173test("a listed service token still needs a valid signature and audience", async () => {
174 const forged = await sign(claims({ email: undefined, common_name: CLIENT }), { key: stranger.privateKey });
175 assert.deepEqual(await authorize(request(forged), SETTINGS, { fetcher, now: NOW }), { ok: false, reason: "bad signature" });
176 const elsewhere = await sign(claims({ email: undefined, common_name: CLIENT, aud: ["b".repeat(64)] }));
177 assert.deepEqual(await authorize(request(elsewhere), SETTINGS, { fetcher, now: NOW }), { ok: false, reason: "wrong audience" });
178});
179
180test("an email wins over a client id on the same token", async () => {
181 const token = await sign(claims({ email: "someone@example.com", common_name: CLIENT }));
182 const result = await authorize(request(token), SETTINGS, { fetcher, now: NOW });
183 assert.deepEqual(result, { ok: false, reason: "not staff", email: "someone@example.com" });
184});
185
186test("service tokens are read as client id to name, dropping malformed entries", () => {
187 assert.deepEqual(
188 parseServiceTokens(` ${CLIENT}=claude , short.access=x, abcdefabcdefabcdef.access=Bad Name, abcdefabcdefabcdef.access=`),
189 new Map([[CLIENT, "claude"]]),
190 );
191 assert.deepEqual(parseServiceTokens(""), new Map());
192});
193
Put the stylesheet at the top of the head, before React Router's preloads194test("staff emails match without regard to case", async () => {
195 const result = await authorize(request(await sign(claims({ email: "Owner@G1T.sh" }))), SETTINGS, { fetcher, now: NOW });
196 assert.deepEqual(result, { ok: true, email: "owner@g1t.sh" });
197});
198
199test("a request without a token is refused", async () => {
200 assert.deepEqual(await authorize(request(), SETTINGS, { fetcher, now: NOW }), { ok: false, reason: "no Access token" });
201});
202
203test("garbage is refused", async () => {
204 for (const token of ["", "a.b", "a.b.c.d", "!!.??.**", "e30.e30.e30"]) {
205 const result = await verifyAccessJwt(token, SETTINGS, { fetcher, now: NOW });
206 assert.equal(result.ok, false, token);
207 }
208});
209
210test("the team's keys are fetched once and kept for a few minutes", async () => {
211 await verifyAccessJwt(await sign(claims()), SETTINGS, { fetcher, now: NOW });
212 await verifyAccessJwt(await sign(claims()), SETTINGS, { fetcher, now: NOW + 60_000 });
213 assert.equal(fetches.length, 1);
214 await verifyAccessJwt(await sign(claims()), SETTINGS, { fetcher, now: NOW + 10 * 60_000 });
215 assert.equal(fetches.length, 2);
216});
217
218test("when the keys cannot be fetched, nothing is let in", async () => {
219 const down = async () => new Response("no", { status: 503 });
220 const result = await verifyAccessJwt(await sign(claims()), SETTINGS, { fetcher: down, now: NOW });
221 assert.deepEqual(result, { ok: false, reason: "unknown signing key" });
222});
223
224test("sudo is closed until every setting is given", () => {
225 const full = { ACCESS_TEAM_DOMAIN: "https://g1t.cloudflareaccess.com/", ACCESS_AUD: AUD, STAFF_EMAILS: "A@g1t.sh, b@g1t.sh" };
sudo: Access service tokens listed in STAFF_SERVICE_TOKENS are staff, recorded as <name>@service.g1t.sh226 assert.deepEqual(readSettings(full), { teamDomain: TEAM, aud: AUD, staff: ["a@g1t.sh", "b@g1t.sh"], services: new Map() });
227 assert.deepEqual(readSettings({ ...full, STAFF_SERVICE_TOKENS: `${CLIENT}=claude` })?.services, new Map([[CLIENT, "claude"]]));
Put the stylesheet at the top of the head, before React Router's preloads228 assert.equal(readSettings({ ...full, ACCESS_AUD: "" }), null);
229 assert.equal(readSettings({ ...full, ACCESS_TEAM_DOMAIN: "" }), null);
230 assert.equal(readSettings({ ...full, STAFF_EMAILS: " , " }), null);
231 assert.equal(readSettings({ ...full, ACCESS_TEAM_DOMAIN: "evil.example.com" }), null);
232 assert.equal(readSettings({}), null);
233});
234
235test("changes are only taken from sudo's own pages", () => {
236 const post = (headers: Record<string, string>) => new Request("https://sudo.g1t.sh/x", { method: "POST", headers });
237 assert.equal(isSameOrigin(post({ origin: "https://sudo.g1t.sh" })), true);
238 assert.equal(isSameOrigin(post({ referer: "https://sudo.g1t.sh/accounts/x" })), true);
239 assert.equal(isSameOrigin(post({ origin: "https://evil.example" })), false);
240 assert.equal(isSameOrigin(post({ origin: "null" })), false);
241 assert.equal(isSameOrigin(post({ referer: "https://sudo.g1t.sh.evil.example/" })), false);
242 assert.equal(isSameOrigin(post({ origin: "https://sudo.g1t.sh", "sec-fetch-site": "cross-site" })), false);
243 assert.equal(isSameOrigin(post({})), false);
244});
245
246test("everyone at a staff domain is staff, and nobody at a lookalike", () => {
247 const staff = parseStaff("syntaqx@gmail.com, @g1t.sh");
248 assert.deepEqual(staff, ["syntaqx@gmail.com", "@g1t.sh"]);
249 assert.equal(isStaff("syntaqx@gmail.com", staff), true);
250 assert.equal(isStaff("ada@g1t.sh", staff), true);
251 assert.equal(isStaff("ada@xg1t.sh", staff), false);
252 assert.equal(isStaff("ada@g1t.sh.evil.com", staff), false);
253 assert.equal(isStaff("someone@gmail.com", staff), false);
254 assert.equal(isStaff("@g1t.sh", staff), false);
255 assert.equal(isStaff("a@b@g1t.sh", staff), false);
256});

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