import { decryptField, encryptField, panLookup } from '../src/services/fieldCrypto.js'; /** * Widen bank columns and encrypt values already stored in plaintext. * @param {import('knex').Knex} knex */ export async function up(knex) { await knex.schema.alterTable('applications', (table) => { table.string('pan', 255).nullable().alter(); table.string('account_number', 255).nullable().alter(); }); const hasLookup = await knex.schema.hasColumn('applications', 'pan_lookup'); if (!hasLookup) { await knex.schema.alterTable('applications', (table) => { table.string('pan_lookup', 64).nullable().index(); }); } const rows = await knex('applications').select('id', 'pan', 'account_number', 'pan_lookup'); for (const row of rows) { /** @type {Record} */ const updates = {}; if (row.pan && !String(row.pan).startsWith('enc:v1:')) { updates.pan_lookup = panLookup(String(row.pan)); updates.pan = encryptField(String(row.pan)); } if (row.account_number && !String(row.account_number).startsWith('enc:v1:')) { updates.account_number = encryptField(String(row.account_number)); } if (Object.keys(updates).length > 0) { await knex('applications').where({ id: row.id }).update(updates); } } } /** * @param {import('knex').Knex} knex */ export async function down(knex) { const rows = await knex('applications').select('id', 'pan', 'account_number'); for (const row of rows) { /** @type {Record} */ const updates = {}; if (row.pan && String(row.pan).startsWith('enc:v1:')) { updates.pan = decryptField(row.pan); } if (row.account_number && String(row.account_number).startsWith('enc:v1:')) { updates.account_number = decryptField(row.account_number); } if (Object.keys(updates).length > 0) { await knex('applications').where({ id: row.id }).update(updates); } } await knex.schema.alterTable('applications', (table) => { table.dropColumn('pan_lookup'); table.string('pan', 10).nullable().alter(); table.string('account_number', 18).nullable().alter(); }); }