Files
forkmessager/apps/server/prisma/encrypt-existing.ts
T
2026-03-10 21:11:59 +03:00

68 lines
2.6 KiB
TypeScript

/**
* Migrate existing plain-text messages to encrypted form.
*
* Run once after enabling ENCRYPTION_KEY:
* npx ts-node prisma/encrypt-existing.ts
*
* Safe to re-run — skips already-encrypted messages ("enc:v1:" prefix).
*/
import '../src/config'; // loads .env & initialises encryption
import { PrismaClient } from '@prisma/client';
import { encryptText, isEncryptionEnabled } from '../src/encrypt';
// Use raw PrismaClient to bypass the encryption middleware (avoid double-encryption)
const rawPrisma = new PrismaClient();
async function main() {
if (!isEncryptionEnabled()) {
console.error('❌ ENCRYPTION_KEY не задан в .env — сначала укажите ключ шифрования.');
process.exit(1);
}
console.log('🔒 Начало шифрования существующих сообщений…\n');
// We bypass the Prisma middleware by using $queryRawUnsafe for the SELECT,
// then use raw UPDATE to avoid double-encryption via middleware.
const messages: Array<{ id: string; content: string | null; quote: string | null }> =
await rawPrisma.$queryRaw`
SELECT id, content, quote FROM "Message"
WHERE (content IS NOT NULL AND content != '' AND content NOT LIKE 'enc:v1:%')
OR (quote IS NOT NULL AND quote != '' AND quote NOT LIKE 'enc:v1:%')
`;
console.log(`📝 Найдено ${messages.length} незашифрованных сообщений`);
let encrypted = 0;
const BATCH_SIZE = 500;
for (let i = 0; i < messages.length; i += BATCH_SIZE) {
const batch = messages.slice(i, i + BATCH_SIZE);
await rawPrisma.$transaction(
batch.map((msg) => {
const newContent = msg.content && !msg.content.startsWith('enc:v1:')
? encryptText(msg.content) : null;
const newQuote = msg.quote && !msg.quote.startsWith('enc:v1:')
? encryptText(msg.quote) : null;
return rawPrisma.$executeRaw`
UPDATE "Message"
SET content = COALESCE(${newContent}::text, content),
quote = COALESCE(${newQuote}::text, quote)
WHERE id = ${msg.id}
`;
})
);
encrypted += batch.length;
process.stdout.write(` ✔ ${encrypted}/${messages.length}\r`);
}
console.log(`\n\n✅ Готово! Зашифровано ${encrypted} сообщений.`);
console.log('⚠ СОХРАНИТЕ КЛЮЧ ENCRYPTION_KEY В НАДЁЖНОМ МЕСТЕ — без него данные не восстановить!');
await rawPrisma.$disconnect();
}
main().catch((e) => {
console.error('Ошибка миграции:', e);
process.exit(1);
});