ec-nest/prisma/encrypt-idcard.ts
liuyun 394d7a9731 feat(security): id_card_no 存储层 AES-256-GCM 加密 + SHA-256 哈希唯一
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-10-21 12:03:43 +08:00

49 lines
1.5 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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();
});