require('dotenv/config'); const { getConfig } = require('../config'); const { createPrismaClient } = require('../prismaClient'); const { decryptStringOrThrow, encryptStringOrThrow, } = require('../services/crypto'); const { readStoredSecret } = require('../services/notifications/channelConfig'); function asObject(value) { return value && typeof value === 'object' && !Array.isArray(value) ? value : {}; } function parseMode(argv) { if (argv.includes('--encrypt')) { return 'encrypt'; } if (argv.includes('--decrypt')) { return 'decrypt'; } throw new Error('Usage: node src/scripts/migrate-notification-channel-secrets.js --encrypt|--decrypt'); } (async () => { const mode = parseMode(process.argv.slice(2)); const config = getConfig(); const { prisma, pool } = createPrismaClient(); await prisma.$connect(); try { const rows = await prisma.notificationChannel.findMany({ select: { id: true, name: true, config_json: true, }, orderBy: [{ created_at: 'asc' }], }); let updated = 0; let skipped = 0; for (const row of rows) { const current = asObject(row.config_json); const { secretEncrypted, legacySecret } = readStoredSecret(current); if (mode === 'encrypt') { if (!legacySecret) { skipped += 1; continue; } const next = { ...current, secretEncrypted: encryptStringOrThrow(config, legacySecret), }; delete next.secret; await prisma.notificationChannel.update({ where: { id: row.id }, data: { config_json: next, updated_by: null, }, }); updated += 1; continue; } if (!secretEncrypted) { skipped += 1; continue; } const decryptedSecret = decryptStringOrThrow(config, secretEncrypted); if (!decryptedSecret) { throw new Error(`notification_channel_secret_empty_after_decrypt:${row.id}`); } const next = { ...current, secret: decryptedSecret, }; delete next.secretEncrypted; await prisma.notificationChannel.update({ where: { id: row.id }, data: { config_json: next, updated_by: null, }, }); updated += 1; } process.stdout.write(`mode=${mode} updated=${updated} skipped=${skipped}\n`); } finally { await prisma.$disconnect(); await pool.end(); } })().catch((error) => { console.error(error); process.exit(1); });