- FRE-4499 (SpamShield): Verified 6 security fixes (2 High, 4 Medium) - S01: Pre-compiled regex in RuleEngine (ReDoS fix) - S02: SmsClassifier accepts senderPhoneNumber context - S03: AlertServer JWT auth + origin validation - S04: SHA-256 phone hashing (PII protection) - S05: DecisionEngine timeout enforcement via Promise.race - S06: CarrierFactory.getAllCarriers properly async/await - FRE-4500 (Correlation): Verified 7 security fixes (2 Critical, 2 High, 2 Medium, 1 Low) - C1: Ingest endpoints auth via request.user.id - C2: IDOR protection on group endpoints (userId filter) - H3: JWT middleware registered in server.ts - H4: Fastify schema validation on all routes - M6: Payload sanitization with depth limit and circular ref detection - L7: CORS origin restricted to env var - Resolved liveness incidents FRE-4652 and FRE-4654 - All Phase 5 child issues now complete
144 lines
3.6 KiB
TypeScript
144 lines
3.6 KiB
TypeScript
import {
|
|
AlertSource,
|
|
AlertCategory,
|
|
Severity,
|
|
EntityType,
|
|
NormalizedAlertInput,
|
|
CorrelationGroupOutput,
|
|
CorrelatedAlertOutput,
|
|
CorrelationQuery,
|
|
} from "@shieldai/types";
|
|
import { alertNormalizer, AlertNormalizer } from "./normalizer";
|
|
import { correlationEngine, CorrelationEngine } from "./engine";
|
|
|
|
export class CorrelationService {
|
|
private normalizer: AlertNormalizer;
|
|
private engine: CorrelationEngine;
|
|
|
|
constructor(
|
|
normalizer: AlertNormalizer = alertNormalizer,
|
|
engine: CorrelationEngine = correlationEngine
|
|
) {
|
|
this.normalizer = normalizer;
|
|
this.engine = engine;
|
|
}
|
|
|
|
public async ingestDarkWatchAlert(
|
|
userId: string,
|
|
sourceAlertId: string,
|
|
payload: {
|
|
exposureId: string;
|
|
breachName: string;
|
|
severity: string;
|
|
channel: string;
|
|
dataType?: string[];
|
|
dataSource?: string;
|
|
},
|
|
timestamp?: Date
|
|
): Promise<CorrelatedAlertOutput> {
|
|
const normalized = this.normalizer.normalizeDarkWatchAlert(
|
|
userId,
|
|
sourceAlertId,
|
|
payload,
|
|
timestamp
|
|
);
|
|
return this.engine.ingestAlert(normalized);
|
|
}
|
|
|
|
public async ingestSpamShieldAlert(
|
|
userId: string,
|
|
sourceAlertId: string,
|
|
payload: {
|
|
phoneNumber: string;
|
|
decision: string;
|
|
confidence: number;
|
|
reasons?: string[];
|
|
channel?: "call" | "sms";
|
|
hiyaReputationScore?: number;
|
|
truecallerSpamScore?: number;
|
|
},
|
|
timestamp?: Date
|
|
): Promise<CorrelatedAlertOutput> {
|
|
const normalized = this.normalizer.normalizeSpamShieldAlert(
|
|
userId,
|
|
sourceAlertId,
|
|
payload,
|
|
timestamp
|
|
);
|
|
return this.engine.ingestAlert(normalized);
|
|
}
|
|
|
|
public async ingestVoicePrintAlert(
|
|
userId: string,
|
|
sourceAlertId: string,
|
|
payload: {
|
|
jobId: string;
|
|
verdict: string;
|
|
syntheticScore: number;
|
|
confidence: number;
|
|
matchedEnrollmentId?: string;
|
|
matchedSimilarity?: number;
|
|
analysisType?: string;
|
|
},
|
|
timestamp?: Date
|
|
): Promise<CorrelatedAlertOutput> {
|
|
const normalized = this.normalizer.normalizeVoicePrintAlert(
|
|
userId,
|
|
sourceAlertId,
|
|
payload,
|
|
timestamp
|
|
);
|
|
return this.engine.ingestAlert(normalized);
|
|
}
|
|
|
|
public async ingestCallAnalysisAlert(
|
|
userId: string,
|
|
sourceAlertId: string,
|
|
payload: {
|
|
callId: string;
|
|
eventType?: string;
|
|
mosScore?: number;
|
|
anomaly?: string;
|
|
sentiment?: { label: string; score: number };
|
|
},
|
|
timestamp?: Date
|
|
): Promise<CorrelatedAlertOutput> {
|
|
const normalized = this.normalizer.normalizeCallAnalysisAlert(
|
|
userId,
|
|
sourceAlertId,
|
|
payload,
|
|
timestamp
|
|
);
|
|
return this.engine.ingestAlert(normalized);
|
|
}
|
|
|
|
public async ingestGenericAlert(
|
|
input: NormalizedAlertInput
|
|
): Promise<CorrelatedAlertOutput> {
|
|
return this.engine.ingestAlert(input);
|
|
}
|
|
|
|
public getCorrelatedAlerts(query: CorrelationQuery) {
|
|
return this.engine.getCorrelatedAlerts(query);
|
|
}
|
|
|
|
public getCorrelationGroups(query: CorrelationQuery) {
|
|
return this.engine.getCorrelationGroups(query);
|
|
}
|
|
|
|
public getGroupById(groupId: string, userId: string) {
|
|
return this.engine.getGroupById(groupId, userId);
|
|
}
|
|
|
|
public resolveGroup(groupId: string, userId: string, status?: string) {
|
|
return this.engine.resolveGroup(groupId, userId, status as any);
|
|
}
|
|
|
|
public getDashboardData(userId: string, timeWindowMinutes?: number) {
|
|
return this.engine.getDashboardData(userId, timeWindowMinutes);
|
|
}
|
|
}
|
|
|
|
export const correlationService = new CorrelationService();
|
|
export { alertNormalizer, correlationEngine };
|