@mitre-attack/attack-data-model
Version:
A TypeScript API for the MITRE ATT&CK data model
138 lines (136 loc) • 4.3 kB
JavaScript
// src/schemas/common/attack-id.ts
import { z } from "zod/v4";
var attackIdConfig = {
tactic: {
pattern: /^TA\d{4}$/,
message: "Must match ATT&CK Tactic ID format (TA####)",
example: "TA####",
stixTypes: ["x-mitre-tactic"]
},
technique: {
pattern: /^T\d{4}$/,
message: "Must match ATT&CK Technique ID format (T####)",
example: "T####",
stixTypes: ["attack-pattern"]
// Note: attack-pattern can be technique or subtechnique
},
subtechnique: {
pattern: /^T\d{4}\.\d{3}$/,
message: "Must match ATT&CK Sub-technique ID format (T####.###)",
example: "T####.###",
stixTypes: ["attack-pattern"]
// Note: attack-pattern can be technique or subtechnique
},
group: {
pattern: /^G\d{4}$/,
message: "Must match ATT&CK Group ID format (G####)",
example: "G####",
stixTypes: ["intrusion-set"]
},
software: {
pattern: /^S\d{4}$/,
message: "Must match ATT&CK Software ID format (S####)",
example: "S####",
stixTypes: ["malware", "tool"]
},
mitigation: {
pattern: /^M\d{4}$/,
message: "Must match ATT&CK Mitigation ID format (M####)",
example: "M####",
stixTypes: ["course-of-action"]
},
asset: {
pattern: /^A\d{4}$/,
message: "Must match ATT&CK Asset ID format (A####)",
example: "A####",
stixTypes: ["x-mitre-asset"]
},
"data-source": {
pattern: /^DS\d{4}$/,
message: "Must match ATT&CK Data Source ID format (DS####)",
example: "DS####",
stixTypes: ["x-mitre-data-source"]
},
"log-source": {
pattern: /^LS\d{4}$/,
message: "Must match ATT&CK Log Source ID format (DS####)",
example: "LS####",
stixTypes: ["x-mitre-log-source"]
},
campaign: {
pattern: /^C\d{4}$/,
message: "Must match ATT&CK Campaign ID format (C####)",
example: "C####",
stixTypes: ["campaign"]
},
"data-component": {
pattern: /^DC\d{4}$/,
message: "Must match ATT&CK Data Component Source ID format (DC####)",
example: "DC####",
stixTypes: ["x-mitre-data-component"]
},
"detection-strategy": {
pattern: /^DET\d{4}$/,
message: "Must match ATT&CK Detection Strategy Source ID format (DET####)",
example: "DET####",
stixTypes: ["x-mitre-detection-strategy"]
},
analytic: {
pattern: /^AN\d{4}$/,
message: "Must match ATT&CK Analytic Source ID format (AN####)",
example: "AN####",
stixTypes: ["x-mitre-analytic"]
}
};
var stixTypeToAttackIdMapping = {
"x-mitre-tactic": "tactic",
"attack-pattern": "technique",
// Default to technique; subtechnique handling is done contextually
"intrusion-set": "group",
malware: "software",
tool: "software",
"course-of-action": "mitigation",
"x-mitre-asset": "asset",
"x-mitre-data-source": "data-source",
campaign: "campaign",
"x-mitre-data-component": "data-component",
"x-mitre-log-source": "log-source",
"x-mitre-detection-strategy": "detection-strategy",
"x-mitre-analytic": "analytic"
};
var attackIdPatterns = Object.fromEntries(
Object.entries(attackIdConfig).map(([key, config]) => [key, config.pattern])
);
var attackIdMessages = Object.fromEntries(
Object.entries(attackIdConfig).map(([key, config]) => [key, config.message])
);
var attackIdExamples = Object.fromEntries(
Object.entries(attackIdConfig).map(([key, config]) => [key, config.example])
);
function getAttackIdExample(stixType) {
if (stixType === "attack-pattern") {
return `${attackIdExamples.technique} or ${attackIdExamples.subtechnique}`;
}
const attackIdType = stixTypeToAttackIdMapping[stixType];
return attackIdExamples[attackIdType];
}
var createAttackIdSchema = (stixType) => {
const attackIdType = stixTypeToAttackIdMapping[stixType];
if (stixType === "attack-pattern") {
return z.string().refine(
(id) => attackIdPatterns.technique.test(id) || attackIdPatterns.subtechnique.test(id),
{
error: `Must match either ATT&CK Technique ID format (${attackIdExamples.technique}) or Sub-technique ID format (${attackIdExamples.subtechnique})`
}
);
}
return z.string().regex(attackIdPatterns[attackIdType], attackIdMessages[attackIdType]);
};
export {
stixTypeToAttackIdMapping,
attackIdPatterns,
attackIdMessages,
attackIdExamples,
getAttackIdExample,
createAttackIdSchema
};