CodeIssuesDiscussionsWikiPull RequestsProjectsCommitsActionsReleasesContributorsPulse● GatesSecuritySettingsDeploymentsPipelineInsightsAgents✨ Explain✨ Ask AI✨ Workspace✨ Spec✨ Tests▓ Debt Map✨ NL Search🏛 Archaeology
Blame · Line-by-line history
invite-tokens.ts
Each line is annotated with the commit that last touched it. Click any SHA to jump to that commit and see the surrounding change.
| febd4f0 | 1 | /** |
| 2 | * Invite tokens — opaque secrets used to gate collaborator invitation links. | |
| 3 | * | |
| 4 | * The plaintext token is emailed to the invitee as a URL fragment; only its | |
| 5 | * sha256 hash is persisted on the `repo_collaborators` row. When the invitee | |
| 6 | * clicks the link, we re-hash the presented token and match it against the | |
| 7 | * stored hash. Storing only the hash means a DB compromise does not leak | |
| 8 | * live invite URLs. | |
| 9 | * | |
| 10 | * Token format: 32 hex chars (16 bytes of entropy). Plenty of collision | |
| 11 | * resistance for short-lived single-use invites, and short enough to paste. | |
| 12 | */ | |
| 13 | ||
| 14 | import { randomBytes, createHash } from "crypto"; | |
| 15 | ||
| 16 | /** | |
| 17 | * Generate a fresh invite token — 32 hex chars, cryptographically random. | |
| 18 | */ | |
| 19 | export function generateInviteToken(): string { | |
| 20 | return randomBytes(16).toString("hex"); | |
| 21 | } | |
| 22 | ||
| 23 | /** | |
| 24 | * Hash an invite token for storage/lookup. Deterministic sha256 hex so the | |
| 25 | * same token always maps to the same row. | |
| 26 | */ | |
| 27 | export function hashInviteToken(token: string): string { | |
| 28 | return createHash("sha256").update(token).digest("hex"); | |
| 29 | } |