23 lines
1.1 KiB
JavaScript
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');
|
|
};
|