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.
| Team plan, an open-source pool, monthly trials and honest metering; the sidebar for everyone; a workspace that stays put | 1 | /** |
| 2 | * Where to send someone after they sign in, sign up or switch account: | |
| 3 | * a path on g1t, and never anywhere else. | |
| 4 | * | |
| 5 | * Only a plain same-origin path is honoured. `//host`, `/\host` and paths | |
| 6 | * with control characters are refused, because browsers read all of them | |
| 7 | * as another site (they drop tabs and newlines, and treat `\` as `/`). | |
| 8 | */ | |
| 9 | export function safeNext(raw: string | null | undefined): string { | |
| 10 | if (!raw || !raw.startsWith("/")) return "/"; | |
| 11 | if (raw.startsWith("//") || raw.includes("\\")) return "/"; | |
| 12 | // Control characters and DEL, which a browser may strip before parsing. | |
| 13 | if (/[\u0000-\u001f\u007f]/.test(raw)) return "/"; | |
| 14 | try { | |
| 15 | const base = "https://g1t.invalid"; | |
| 16 | const url = new URL(raw, base); | |
| 17 | if (url.origin !== base) return "/"; | |
| 18 | return url.pathname + url.search + url.hash; | |
| 19 | } catch { | |
| 20 | return "/"; | |
| 21 | } | |
| 22 | } | |
| 23 | ||
| 24 | /** A sign-in or sign-up page that brings someone back to `here` afterwards. */ | |
| 25 | export function withNext(page: "/login" | "/register", here: string): string { | |
| 26 | const next = safeNext(here); | |
| 27 | return next === "/" ? page : `${page}?next=${encodeURIComponent(next)}`; | |
| 28 | } |