pediatric-ai-scribe-v3/migrations/1781000000000_invite-code-recoverable.js
2026-09-12 21:00:22 +02:00

23 lines
1.1 KiB
JavaScript

// Invite codes were shown once and never again: only a SHA-256 hash and the
// last four characters were kept. That is the right shape for a password and
// the wrong one for an invitation, which has to be given to somebody — usually
// not at the moment it is created, and often more than once.
//
// The code is now also stored encrypted with DATA_ENCRYPTION_KEY, the same
// AES-256-GCM treatment as Nextcloud tokens and image prompts. The hash stays:
// it is what a claim looks up, it is indexed, and a claim must not depend on
// decrypting every row.
//
// What this costs, stated plainly: a code is recoverable by anyone who holds
// both the database and the encryption key, where before it was recoverable by
// nobody. An invitation is a low-value secret — it grants registration, not
// access — and it expires. Existing rows keep working and stay unrecoverable;
// they simply have no cipher to show.
exports.up = async function (pgm) {
pgm.sql('ALTER TABLE registration_invites ADD COLUMN IF NOT EXISTS code_cipher TEXT');
};
exports.down = async function (pgm) {
pgm.sql('ALTER TABLE registration_invites DROP COLUMN IF EXISTS code_cipher');
};