49 lines
1.5 KiB
TypeScript
49 lines
1.5 KiB
TypeScript
import 'dotenv/config';
|
||
import { PrismaClient } from '@prisma/client';
|
||
import { encrypt, hash } from '../src/common/id-card-cipher.js';
|
||
|
||
/**
|
||
* id_card_no 加密回填脚本(迁移 A 之后、迁移 B 之前运行一次)。
|
||
*
|
||
* 遍历 ltc_elder / ltc_staff,读取明文 `id_card_no`,计算
|
||
* `id_card_no_hash = SHA-256(明文)`、`id_card_no_enc = AES-256-GCM(明文)`,回写两列。
|
||
* 幂等:可重复执行(按主键逐行覆盖)。
|
||
*
|
||
* 运行:pnpm exec tsx prisma/encrypt-idcard.ts
|
||
*/
|
||
const prisma = new PrismaClient();
|
||
|
||
async function backfill(table: 'ltc_elder' | 'ltc_staff'): Promise<number> {
|
||
const rows = await prisma.$queryRawUnsafe<Array<{ id: string; id_card_no: string | null }>>(
|
||
`SELECT id, id_card_no FROM ${table} WHERE id_card_no IS NOT NULL AND id_card_no <> ''`,
|
||
);
|
||
let updated = 0;
|
||
for (const row of rows) {
|
||
const plain = row.id_card_no as string;
|
||
await prisma.$executeRawUnsafe(
|
||
`UPDATE ${table} SET id_card_no_hash = ?, id_card_no_enc = ? WHERE id = ?`,
|
||
hash(plain),
|
||
encrypt(plain),
|
||
row.id,
|
||
);
|
||
updated += 1;
|
||
}
|
||
console.log(`${table}: 回填 ${updated} 行`);
|
||
return updated;
|
||
}
|
||
|
||
async function main(): Promise<void> {
|
||
const elderCount = await backfill('ltc_elder');
|
||
const staffCount = await backfill('ltc_staff');
|
||
console.log(`回填完成:elder=${elderCount} staff=${staffCount}`);
|
||
}
|
||
|
||
main()
|
||
.catch((e) => {
|
||
console.error(e);
|
||
process.exitCode = 1;
|
||
})
|
||
.finally(async () => {
|
||
await prisma.$disconnect();
|
||
});
|