feat(crm): 实现GDPR Article 17数据库级个人数据级联擦除与雷达IP掩码脱敏
这个提交包含在:
@@ -1,6 +1,10 @@
|
||||
import { Provide } from '@midwayjs/core';
|
||||
import { BaseService } from '@cool-midway/core';
|
||||
import { InjectEntityModel } from '@midwayjs/typeorm';
|
||||
import { Repository } from 'typeorm';
|
||||
import * as crypto from 'crypto';
|
||||
import { CrmLeadEntity } from '../entity/lead';
|
||||
import { RadarTrackEntity } from '../entity/track';
|
||||
|
||||
export interface GdprUserDataBundle {
|
||||
subjectId: string;
|
||||
@@ -68,6 +72,12 @@ export function anonymizePiiData(rawRecord: {
|
||||
*/
|
||||
@Provide()
|
||||
export class ComplianceGdprService extends BaseService {
|
||||
@InjectEntityModel(CrmLeadEntity)
|
||||
crmLeadEntity?: Repository<CrmLeadEntity>;
|
||||
|
||||
@InjectEntityModel(RadarTrackEntity)
|
||||
crmTrackEntity?: Repository<RadarTrackEntity>;
|
||||
|
||||
/**
|
||||
* 打包主体全量便携数据 (GDPR Article 20)
|
||||
*/
|
||||
@@ -100,4 +110,52 @@ export class ComplianceGdprService extends BaseService {
|
||||
certificateHash,
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* 真正级联执行数据库级的个人数据擦除与雷达 IP 掩码脱敏 (GDPR Article 17)
|
||||
*/
|
||||
async purgeVisitorPersonalData(subject: {
|
||||
email?: string;
|
||||
leadId?: number | string;
|
||||
visitorId?: string;
|
||||
}): Promise<ErasureReceipt> {
|
||||
const subjectId =
|
||||
subject.email || subject.visitorId || String(subject.leadId || 'anonymous');
|
||||
|
||||
// 1. 清洗线索表 PII 隐私数据
|
||||
if (this.crmLeadEntity) {
|
||||
let lead: CrmLeadEntity | null = null;
|
||||
if (subject.leadId) {
|
||||
lead = await this.crmLeadEntity.findOne({
|
||||
where: { id: Number(subject.leadId) },
|
||||
});
|
||||
} else if (subject.email) {
|
||||
lead = await this.crmLeadEntity.findOne({
|
||||
where: { email: subject.email },
|
||||
});
|
||||
}
|
||||
if (lead) {
|
||||
const cleaned = anonymizePiiData(lead);
|
||||
await this.crmLeadEntity.save(cleaned);
|
||||
}
|
||||
}
|
||||
|
||||
// 2. 掩码雷达足迹 IP
|
||||
if (this.crmTrackEntity && subject.visitorId) {
|
||||
const tracks = await this.crmTrackEntity.find({
|
||||
where: { visitorId: subject.visitorId },
|
||||
});
|
||||
if (Array.isArray(tracks) && tracks.length > 0) {
|
||||
for (const track of tracks) {
|
||||
if (track.ip) {
|
||||
track.ip = maskIpAddress(track.ip);
|
||||
}
|
||||
}
|
||||
await this.crmTrackEntity.save(tracks);
|
||||
}
|
||||
}
|
||||
|
||||
// 3. 签发合规销毁证书
|
||||
return await this.executeRightToBeForgotten(subjectId);
|
||||
}
|
||||
}
|
||||
|
||||
在新工单中引用
屏蔽一个用户