Skip to content
48 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.

The runner base keeps its old comment, so the pushed base image still matches its folder1// Creates a user (or resets their password) in the remote D1 database and
2// writes the generated password to the gitignored .credentials directory.
3//
4// node scripts/create-user.mjs <username> [email]
5import { execSync } from "node:child_process";
6import { pbkdf2Sync, randomBytes } from "node:crypto";
7import { mkdirSync, rmSync, writeFileSync } from "node:fs";
8import { tmpdir } from "node:os";
9import { join } from "node:path";
10
11const [username, email] = process.argv.slice(2);
12if (!/^[a-z0-9](?:[a-z0-9]|-(?=[a-z0-9])){0,38}$/.test(username ?? "")) {
13 console.error("usage: node scripts/create-user.mjs <username> [email]");
14 process.exit(1);
15}
16if (email && !/^[^\s'@]+@[^\s'@]+$/.test(email)) {
17 console.error("invalid email");
18 process.exit(1);
19}
20
21// Must match hashPassword in src/crypto.ts.
22const iterations = 100_000;
23const password = randomBytes(18).toString("base64url");
24const salt = randomBytes(16);
25const hash = pbkdf2Sync(password, salt, iterations, 32, "sha256");
26const stored = `pbkdf2$${iterations}$${salt.toString("base64")}$${hash.toString("base64")}`;
27
28const sqlFile = join(tmpdir(), `g1t-create-user-${process.pid}.sql`);
29writeFileSync(
30 sqlFile,
31 `INSERT INTO users (id, username, email, password_hash)
32 VALUES ('usr_' || lower(hex(randomblob(13))), '${username}', ${email ? `'${email}'` : "NULL"}, '${stored}')
33 ON CONFLICT (username) DO UPDATE SET password_hash = excluded.password_hash;`,
34);
35try {
36 execSync(`npx wrangler d1 execute g1t --remote --yes --file "${sqlFile}"`, {
37 cwd: join(import.meta.dirname, ".."),
38 stdio: ["ignore", "ignore", "inherit"],
39 });
40} finally {
41 rmSync(sqlFile, { force: true });
42}
43
44const directory = join(import.meta.dirname, "../../../.credentials");
45mkdirSync(directory, { recursive: true });
46const file = join(directory, `${username}.txt`);
47writeFileSync(file, `username: ${username}\npassword: ${password}\n`);
48console.log(`Password for ${username} written to ${file}`);

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