Compare changes
Choose two branches to see what one has that the other does not, then open a pull request for it.
2 commits
- sudo: Access is on, and everyone at g1t.sh is staffChase Pierce81e29c8
- updating claude settingsChase Pierce1df9148
6 files+43−110/6 viewed
| 1 | + | worktrees/* |
| 6 | 6 | "Bash(npx wrangler d1 migrations list:*)", | |
| 7 | 7 | "Bash(npx wrangler secret put:*)", | |
| 8 | 8 | "Bash(npx wrangler tail:*)", | |
| 9 | − | "Bash(npm run deploy:*)" | |
| 9 | + | "Bash(npm run deploy:*)", | |
| 10 | + | "Bash(bash */ship-deployments.sh)", | |
| 11 | + | "Bash(CLOUDFLARE_API_TOKEN= npx wrangler:*)", | |
| 12 | + | "Bash(npx wrangler:*)" | |
| 10 | 13 | ] | |
| 11 | 14 | } | |
| 12 | 15 | } |
| 35 | 35 | - Application name: `sudo`. | |
| 36 | 36 | - Session duration: short, such as 8 hours. | |
| 37 | 37 | - Public hostname: `sudo.g1t.sh` (path empty, so it covers everything). | |
| 38 | − | 2. **Add a policy:** action *Allow*, include *Emails* → the owner's address | |
| 39 | − | (the same addresses as `STAFF_EMAILS`). Add more staff here *and* in | |
| 40 | − | `STAFF_EMAILS`; either one alone is not enough. | |
| 38 | + | 2. **Add a policy** (`g1t staff`): action *Allow*, include *Emails* → the | |
| 39 | + | owner's address, and *Emails ending in* → `g1t.sh` for everyone with a | |
| 40 | + | g1t address (the same entries as `STAFF_EMAILS`, where a domain is | |
| 41 | + | written `@g1t.sh`). Add more staff here *and* in `STAFF_EMAILS`; either | |
| 42 | + | one alone is not enough. | |
| 41 | 43 | 3. Save, then open the application's **Overview** (or *Basic information*) | |
| 42 | 44 | and copy the **Application Audience (AUD) tag**. | |
| 43 | 45 | 4. Find the **team domain** under **Zero Trust → Settings → Custom pages** | |
| 48 | 50 | "vars": { | |
| 49 | 51 | "ACCESS_TEAM_DOMAIN": "<team>.cloudflareaccess.com", | |
| 50 | 52 | "ACCESS_AUD": "<the AUD tag>", | |
| 51 | − | "STAFF_EMAILS": "syntaqx@gmail.com" | |
| 53 | + | "STAFF_EMAILS": "syntaqx@gmail.com, @g1t.sh" | |
| 52 | 54 | } | |
| 53 | 55 | ``` | |
| 54 | 56 |
| 6 | 6 | authorize, | |
| 7 | 7 | clearKeyCache, | |
| 8 | 8 | isSameOrigin, | |
| 9 | + | isStaff, | |
| 10 | + | parseStaff, | |
| 9 | 11 | readSettings, | |
| 10 | 12 | verifyAccessJwt, | |
| 11 | 13 | } from "./access.ts"; | |
| 204 | 206 | assert.equal(isSameOrigin(post({ origin: "https://sudo.g1t.sh", "sec-fetch-site": "cross-site" })), false); | |
| 205 | 207 | assert.equal(isSameOrigin(post({})), false); | |
| 206 | 208 | }); | |
| 209 | + | ||
| 210 | + | test("everyone at a staff domain is staff, and nobody at a lookalike", () => { | |
| 211 | + | const staff = parseStaff("syntaqx@gmail.com, @g1t.sh"); | |
| 212 | + | assert.deepEqual(staff, ["syntaqx@gmail.com", "@g1t.sh"]); | |
| 213 | + | assert.equal(isStaff("syntaqx@gmail.com", staff), true); | |
| 214 | + | assert.equal(isStaff("ada@g1t.sh", staff), true); | |
| 215 | + | assert.equal(isStaff("ada@xg1t.sh", staff), false); | |
| 216 | + | assert.equal(isStaff("ada@g1t.sh.evil.com", staff), false); | |
| 217 | + | assert.equal(isStaff("someone@gmail.com", staff), false); | |
| 218 | + | assert.equal(isStaff("@g1t.sh", staff), false); | |
| 219 | + | assert.equal(isStaff("a@b@g1t.sh", staff), false); | |
| 220 | + | }); |
| 26 | 26 | teamDomain: string; | |
| 27 | 27 | /** The Access application's Audience (AUD) tag. */ | |
| 28 | 28 | aud: string; | |
| 29 | − | /** Lowercased staff emails. */ | |
| 29 | + | /** Lowercased staff emails, and `@domain` for everyone at a domain. */ | |
| 30 | 30 | staff: string[]; | |
| 31 | 31 | }; | |
| 32 | 32 | ||
| 62 | 62 | return /^[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?\.cloudflareaccess\.com$/.test(host) ? host : null; | |
| 63 | 63 | } | |
| 64 | 64 | ||
| 65 | + | /** | |
| 66 | + | * The staff list: emails, and `@g1t.sh` for everyone with an address at | |
| 67 | + | * that domain. Access proves the address belongs to whoever signed in. | |
| 68 | + | */ | |
| 65 | 69 | export function parseStaff(raw: string): string[] { | |
| 66 | 70 | return raw | |
| 67 | 71 | .split(/[,\s]+/) | |
| 68 | 72 | .map((email) => email.trim().toLowerCase()) | |
| 69 | − | .filter((email) => /^[^@\s]+@[^@\s]+$/.test(email)); | |
| 73 | + | .filter((email) => /^[^@\s]*@[a-z0-9.-]+\.[a-z]{2,}$/.test(email)); | |
| 74 | + | } | |
| 75 | + | ||
| 76 | + | /** Whether a signed-in email is on the staff list: exactly, or by its whole domain. */ | |
| 77 | + | export function isStaff(email: string, staff: string[]): boolean { | |
| 78 | + | const at = email.lastIndexOf("@"); | |
| 79 | + | if (at <= 0 || email.indexOf("@") !== at) return false; | |
| 80 | + | const domain = email.slice(at); | |
| 81 | + | return staff.some((entry) => (entry.startsWith("@") ? entry === domain : entry === email)); | |
| 70 | 82 | } | |
| 71 | 83 | ||
| 72 | 84 | export type AccessClaims = { | |
| 234 | 246 | if (!verified.ok) return verified; | |
| 235 | 247 | const email = typeof verified.claims.email === "string" ? verified.claims.email.trim().toLowerCase() : ""; | |
| 236 | 248 | if (!email) return { ok: false, reason: "token has no email" }; | |
| 237 | − | if (!settings.staff.includes(email)) return { ok: false, reason: "not staff", email }; | |
| 249 | + | if (!isStaff(email, settings.staff)) return { ok: false, reason: "not staff", email }; | |
| 238 | 250 | return { ok: true, email }; | |
| 239 | 251 | } | |
| 240 | 252 |
| 16 | 16 | "services": [{ "binding": "BILLING", "service": "g1t-billing" }], | |
| 17 | 17 | "vars": { | |
| 18 | 18 | // The Zero Trust team domain, such as `g1t.cloudflareaccess.com`. | |
| 19 | − | "ACCESS_TEAM_DOMAIN": "", | |
| 19 | + | "ACCESS_TEAM_DOMAIN": "syntaqx.cloudflareaccess.com", | |
| 20 | 20 | // The Access application's Audience (AUD) tag. | |
| 21 | − | "ACCESS_AUD": "", | |
| 21 | + | "ACCESS_AUD": "5479fcf84130fc7ae68c207ae69a81b2aa17d97714443c6f1dddd058c530b8cf", | |
| 22 | 22 | // Who may use sudo, comma separated. Access lets them in; this | |
| 23 | 23 | // decides again, in case the Access policy is ever widened. | |
| 24 | − | "STAFF_EMAILS": "syntaqx@gmail.com" | |
| 24 | + | "STAFF_EMAILS": "syntaqx@gmail.com, @g1t.sh" | |
| 25 | 25 | }, | |
| 26 | 26 | "observability": { "enabled": true }, | |
| 27 | 27 | "upload_source_maps": true |