// Getting back in, and getting somebody else in, from a terminal. // // npm run member:list // npm run member:reset -- ada@example.com new passphrase, printed once // npm run member:add -- new@example.com "Their Name" // // The way back when the last passphrase is lost, short of erasing the database. // It needs shell access, which is the point: the one door that does not open // over HTTP. // // Cloudflare has no shell, so reach the same rows through D1 — // `npx wrangler d1 execute whispers --remote --command "select email from // members"` — or run this locally against the same Turso or Postgres URL. import process from 'node:process'; import './../db.node.js'; import { add, list, resetPassphrase } from '../app/data/members.js'; const [command, ...rest] = process.argv.slice(2); /** * Prints a member list, or says there is none. * * @param {{ email: string, name: string }[]} people * @returns {void} */ const show = (people) => { if (!people.length) { console.log('Nobody yet. The next visitor to /setup claims the site.'); return; } for (const person of people) console.log(` ${person.email.padEnd(32)} ${person.name}`); }; if (command === 'list') { show(await list()); process.exit(0); } if (command === 'reset') { const email = String(rest[0] ?? '').trim().toLowerCase(); if (!email) { console.error('Which one?\n npm run member:reset -- you@example.com'); process.exit(1); } const people = await list(); const person = people.find((row) => row.email === email); if (!person) { console.error(`No account for ${email}. There is:`); show(people); process.exit(1); } const secret = await resetPassphrase(person.id); console.log(`\n ${person.name} <${person.email}>\n ${secret}\n`); console.log('Shown once. It is stored only as a hash.'); process.exit(0); } if (command === 'add') { const email = String(rest[0] ?? '').trim(); const name = rest.slice(1).join(' ').trim(); if (!email || !name) { console.error('Both are needed:\n npm run member:add -- new@example.com "Their Name"'); process.exit(1); } const result = await add({ email, name }); if (!result.ok) { for (const [field, message] of Object.entries(result.errors)) { console.error(` ${field}: ${message}`); } process.exit(1); } console.log(`\n ${result.member.name} <${result.member.email}>\n ${result.passphrase}\n`); console.log('Shown once. Send it to them.'); process.exit(0); } console.error( 'Usage:\n' + ' npm run member:list\n' + ' npm run member:reset -- you@example.com\n' + ' npm run member:add -- new@example.com "Their Name"', ); process.exit(1);