diff --git a/opencti-platform/opencti-front/lang/front/de.json b/opencti-platform/opencti-front/lang/front/de.json index 28bf4f61da39..5e2ffe5669dc 100644 --- a/opencti-platform/opencti-front/lang/front/de.json +++ b/opencti-platform/opencti-front/lang/front/de.json @@ -30,12 +30,12 @@ "Access right": "Zugriffsrecht", "Access security activity": "Zugriff auf Sicherheitsaktivität", "Access stream directly in your browser": "Zugang zum Stream direkt in Ihrem Browser", + "Access this scenario": "Zugriff auf dieses Szenario", "Access to admin functionalities": "Zugang zu Verwaltungsfunktionen", "Access to collaborative creation": "Zugriff auf kollaborative Erstellung", "Access to file indexing": "Zugang zur Dateiindizierung", "Access to support": "Zugriff auf Unterstützung", "Access to support data": "Zugriff auf Supportdaten", - "Access to the scenario": "Zugang zum Szenario", "Accessible for": "Erreichbar für", "accidental": "Versehentlich/Fehler", "Account expiration date": "Ablaufdatum des Kontos", @@ -1490,6 +1490,7 @@ "In progress messages": "Laufende Meldungen", "In progress tasks": "Laufende Aufgaben", "In progress works": "In Arbeit befindliche Arbeiten", + "In response, we have created placeholders for these TTPs.": "Als Antwort darauf haben wir Platzhalter für diese TTPs geschaffen.", "In this report, ": "In diesem Bericht,", "In workbench": "In der Werkbank", "Inactive": "Inaktiv", @@ -1579,7 +1580,9 @@ "INTERNAL_IMPORT_FILE": "Dateien importieren", "INTERNAL_INGESTION": "Dateneingabe", "Interval": "Intervall", - "Interval between injections (in minute)": "Intervall zwischen den Injektionen (in Minuten)", + "Interval between injections (in minutes)": "Intervall zwischen den Injektionen (in Minuten)", + "Interval must be a positive number": "Intervall muss eine positive Zahl sein", + "Interval must be an integer": "Intervall muss eine ganze Zahl sein", "Intrusion set": "Intrusion set", "Intrusion Sets": "Intrusion Sets", "Intrusion sets": "Intrusion-Sets", @@ -1869,6 +1872,7 @@ "Minimum one event type": "Mindestens ein Ereignistyp", "Minimum one notifier": "Mindestens ein Anmelder", "Minimum one organization": "Mindestens eine Organisation ", + "Minimum one platform": "Mindestens eine Plattform", "Minimum one recipient": "Mindestens ein Empfänger", "Minimum one trigger": "Mindestens ein Auslöser", "MinIO": "MinIO", @@ -2031,7 +2035,7 @@ "Number of entities": "Anzahl der Entitäten", "Number of errors": "Anzahl der Fehler", "Number of history entries": "Anzahl der Historieneinträge", - "Number of injects by attack pattern": "Anzahl der Injektionen nach Angriffsmuster", + "Number of injects generated by attack pattern and platform": "Anzahl der Injektionen, die durch Angriffsmuster und Plattform erzeugt wurden", "Number of lowercase chars must be greater or equals to": "Anzahl der Kleinbuchstaben muss größer oder gleich sein", "Number of messages: ": "Anzahl der Nachrichten:", "Number of node(s)": "Anzahl der Knoten(s)", @@ -2655,7 +2659,7 @@ "Signatures": "Signaturen", "Simple export (just the entity)": "Einfacher Export (nur die Entität)", "Simulate": "Simulieren Sie", - "Simulated (emails)": "Simuliert (Emails)", + "Simulated emails (generated by AI)": "Simulierte E-Mails (von AI generiert)", "Simulation type": "Simulationsart", "Size": "Größe", "snort": "SNORT", @@ -2776,6 +2780,7 @@ "takedown_types": "takedown-Typen", "tanium-signal": "Tanium Signal", "Target": "Ziel", + "Targeted architecture": "Gezielte Architektur", "Targeted by this actor": "Von diesem Akteur anvisiert", "Targeted by this intrusion set": "Von diesem Eindringlingsset anvisiert", "Targeted by this malware": "Von dieser Malware anvisiert", @@ -2787,6 +2792,7 @@ "Targeted entity types": "Typen der Zielpersonen", "Targeted in this campaign": "In dieser Kampagne angestrebt", "Targeted in this incident": "Gezielt in diesem Vorfall", + "Targeted platforms": "Gezielte Plattformen", "Targeted sectors": "Gezielte Sektoren", "Targeting knowledge": "Zielgerichtetes Wissen", "Targeting this country": "Dieses Land im Visier", @@ -2822,6 +2828,7 @@ "team": "Organisiertes Team", "Technical": "Technisch", "Technical (payloads)": "Technisch (Nutzlasten)", + "Technical (payloads) requires attack patterns in this entity.": "Technische (Nutzlasten) erfordern Angriffsmuster in dieser Einheit.", "Technical date": "Technisches Datum", "Technical elements (indicators & observables)": "Technische Elemente (Indikatoren & Beobachtungswerte)", "Techniques": "Techniken", @@ -2853,6 +2860,7 @@ "the dedicated page": "der entsprechenden Seite", "The evaluation of the threat activity cannot be provided (lack of data).": "Die Bewertung der Bedrohungsaktivität kann nicht geliefert werden (Datenmangel).", "The following groups require your attention:": "Die folgenden Gruppen erfordern Ihre Aufmerksamkeit:", + "The following TTPs are not covered in your OpenBAS catalog : ": "Die folgenden TTPs sind in Ihrem OpenBAS-Katalog nicht enthalten:", "The importation of the file has been started": "Das Importieren der Datei wurde gestartet", "The main object and the ... relationships/references linked to it will be deleted permanently.": "Das Hauptobjekt und die mit ihm verknüpften {count} Beziehungen/Referenzen werden dauerhaft gelöscht.", "The main object and the ... relationships/references linked to it will be restored.": "Das Hauptobjekt und die mit ihm verknüpften {count} Beziehungen/Referenzen werden wiederhergestellt.", @@ -2868,7 +2876,7 @@ "The retention policy will be applied on global workbenches (workbenches contained in": "Die Aufbewahrungsrichtlinie wird auf globale Werkbänke angewandt (Werkbänke, die in", "The rule has been disabled, clean-up launched...": "Die Regel wurde deaktiviert, Bereinigung eingeleitet...", "The rule has been enabled, rescan of platform data launched...": "Die Regel wurde aktiviert, erneuter Scan der Plattformdaten gestartet...", - "The scenario has been correctly generated in your OpenBAS platform": "Das Szenario wurde korrekt in Ihrer OpenBAS-Plattform generiert", + "The scenario has been correctly generated in your OpenBAS platform.": "Das Szenario wurde in Ihrer OpenBAS-Plattform korrekt erstellt.", "The STIX ID has been removed": "Die STIX-ID wurde entfernt", "The tag has been added": "Das Tag wurde hinzugefügt", "The tag has been removed": "Das Tag wurde entfernt", diff --git a/opencti-platform/opencti-front/lang/front/en.json b/opencti-platform/opencti-front/lang/front/en.json index d0ef1a4e26b8..04b194ed1d92 100644 --- a/opencti-platform/opencti-front/lang/front/en.json +++ b/opencti-platform/opencti-front/lang/front/en.json @@ -30,12 +30,12 @@ "Access right": "Access right", "Access security activity": "Access security activity", "Access stream directly in your browser": "Access stream directly in your browser", + "Access this scenario": "Access this scenario", "Access to admin functionalities": "Access to admin functionalities", "Access to collaborative creation": "Access to collaborative creation", "Access to file indexing": "Access to file indexing", "Access to support": "Access to support", "Access to support data": "Access to support data", - "Access to the scenario": "Access to the scenario", "Accessible for": "Accessible for", "accidental": "Accidental/Mistake", "Account expiration date": "Account expiration date", @@ -1490,6 +1490,7 @@ "In progress messages": "In progress messages", "In progress tasks": "In progress tasks", "In progress works": "In progress works", + "In response, we have created placeholders for these TTPs.": "In response, we have created placeholders for these TTPs.", "In this report, ": "In this report, ", "In workbench": "In workbench", "Inactive": "Inactive", @@ -1579,7 +1580,9 @@ "INTERNAL_IMPORT_FILE": "Files import", "INTERNAL_INGESTION": "Data ingestion", "Interval": "Interval", - "Interval between injections (in minute)": "Interval between injections (in minute)", + "Interval between injections (in minutes)": "Interval between injections (in minutes)", + "Interval must be a positive number": "Interval must be a positive number", + "Interval must be an integer": "Interval must be an integer", "Intrusion set": "Intrusion set", "Intrusion Sets": "Intrusion Sets", "Intrusion sets": "Intrusion sets", @@ -1869,6 +1872,7 @@ "Minimum one event type": "Minimum one event type", "Minimum one notifier": "Minimum one notifier", "Minimum one organization": "Minimum one organization", + "Minimum one platform": "Minimum one platform", "Minimum one recipient": "Minimum one recipient", "Minimum one trigger": "Minimum one trigger", "MinIO": "MinIO", @@ -2031,7 +2035,7 @@ "Number of entities": "Number of entities", "Number of errors": "Number of errors", "Number of history entries": "Number of history entries", - "Number of injects by attack pattern": "Number of injects by attack pattern", + "Number of injects generated by attack pattern and platform": "Number of injects generated by attack pattern and platform", "Number of lowercase chars must be greater or equals to": "Number of lowercase chars must be greater or equals to", "Number of messages: ": "Number of messages: ", "Number of node(s)": "Number of node(s)", @@ -2655,7 +2659,7 @@ "Signatures": "Signatures", "Simple export (just the entity)": "Simple export (just the entity)", "Simulate": "Simulate", - "Simulated (emails)": "Simulated (emails)", + "Simulated emails (generated by AI)": "Simulated emails (generated by AI)", "Simulation type": "Simulation type", "Size": "Size", "snort": "SNORT", @@ -2776,6 +2780,7 @@ "takedown_types": "takedown types", "tanium-signal": "Tanium Signal", "Target": "Target", + "Targeted architecture": "Targeted architecture", "Targeted by this actor": "Targeted by this actor", "Targeted by this intrusion set": "Targeted by this intrusion set", "Targeted by this malware": "Targeted by this malware", @@ -2787,6 +2792,7 @@ "Targeted entity types": "Targeted entity types", "Targeted in this campaign": "Targeted in this campaign", "Targeted in this incident": "Targeted in this incident", + "Targeted platforms": "Targeted platforms", "Targeted sectors": "Targeted sectors", "Targeting knowledge": "Targeting knowledge", "Targeting this country": "Targeting this country", @@ -2822,6 +2828,7 @@ "team": "Organized team", "Technical": "Technical", "Technical (payloads)": "Technical (payloads)", + "Technical (payloads) requires attack patterns in this entity.": "Technical (payloads) requires attack patterns in this entity.", "Technical date": "Technical date", "Technical elements (indicators & observables)": "Technical elements (indicators & observables)", "Techniques": "Techniques", @@ -2853,6 +2860,7 @@ "the dedicated page": "the dedicated page", "The evaluation of the threat activity cannot be provided (lack of data).": "The evaluation of the threat activity cannot be provided (lack of data).", "The following groups require your attention:": "The following groups require your attention:", + "The following TTPs are not covered in your OpenBAS catalog : ": "The following TTPs are not covered in your OpenBAS catalog : ", "The importation of the file has been started": "The importation of the file has been started", "The main object and the ... relationships/references linked to it will be deleted permanently.": "The main object and the {count} relationships/references linked to it will be deleted permanently.", "The main object and the ... relationships/references linked to it will be restored.": "The main object and the {count} relationships/references linked to it will be restored.", @@ -2868,7 +2876,7 @@ "The retention policy will be applied on global workbenches (workbenches contained in": "The retention policy will be applied on global workbenches (workbenches contained in", "The rule has been disabled, clean-up launched...": "The rule has been disabled, clean-up launched...", "The rule has been enabled, rescan of platform data launched...": "The rule has been enabled, rescan of platform data launched...", - "The scenario has been correctly generated in your OpenBAS platform": "The scenario has been correctly generated in your OpenBAS platform", + "The scenario has been correctly generated in your OpenBAS platform.": "The scenario has been correctly generated in your OpenBAS platform.", "The STIX ID has been removed": "The STIX ID has been removed", "The tag has been added": "The tag has been added", "The tag has been removed": "The tag has been removed", diff --git a/opencti-platform/opencti-front/lang/front/es.json b/opencti-platform/opencti-front/lang/front/es.json index 50dd59ae1dea..898722ff9376 100644 --- a/opencti-platform/opencti-front/lang/front/es.json +++ b/opencti-platform/opencti-front/lang/front/es.json @@ -30,12 +30,12 @@ "Access right": "Derecho de acceso", "Access security activity": "Acceder a la actividad de seguridad", "Access stream directly in your browser": "Acceda al stream directamente en su navegador", + "Access this scenario": "Acceder a este escenario", "Access to admin functionalities": "Acceso a las funciones de administración", "Access to collaborative creation": "Acceder a la creación colaborativa", "Access to file indexing": "Acceso a la indexación de archivos", "Access to support": "Acceder al soporte", "Access to support data": "Acceso a datos de apoyo", - "Access to the scenario": "Acceso al escenario", "Accessible for": "Accesible para", "accidental": "Accidente o error", "Account expiration date": "Fecha de caducidad de la cuenta", @@ -1490,6 +1490,7 @@ "In progress messages": "Mensajes en curso", "In progress tasks": "Tareas en curso", "In progress works": "Ejecuciones en curso", + "In response, we have created placeholders for these TTPs.": "En respuesta, hemos creado marcadores de posición para estos TTP.", "In this report, ": "En este informe, ", "In workbench": "En banco de trabajo", "Inactive": "Inactivo", @@ -1579,7 +1580,9 @@ "INTERNAL_IMPORT_FILE": "Importación de ficheros", "INTERNAL_INGESTION": "Ingesta de datos", "Interval": "Intervalo", - "Interval between injections (in minute)": "Intervalo entre inyecciones (en minutos)", + "Interval between injections (in minutes)": "Intervalo entre inyecciones (en minutos)", + "Interval must be a positive number": "El intervalo debe ser un número positivo", + "Interval must be an integer": "El intervalo debe ser un número entero", "Intrusion set": "Set de intrusión", "Intrusion Sets": "Intrusion Sets", "Intrusion sets": "Sets de intrusión", @@ -1869,6 +1872,7 @@ "Minimum one event type": "Mínimo un tipo de evento", "Minimum one notifier": "Mínimo un notificador", "Minimum one organization": "Mínimo una organización", + "Minimum one platform": "Mínimo una plataforma", "Minimum one recipient": "Mínimo un destinatario", "Minimum one trigger": "Mínimo un disparador", "MinIO": "MinIO", @@ -2031,7 +2035,7 @@ "Number of entities": "Número de entidades", "Number of errors": "Número de erores", "Number of history entries": "Número de entradas del historial", - "Number of injects by attack pattern": "Número de inyecciones por patrón de ataque", + "Number of injects generated by attack pattern and platform": "Número de inyecciones generadas por el patrón de ataque y la plataforma", "Number of lowercase chars must be greater or equals to": "Número de caracteres en minúscula debe ser mayor o igual a", "Number of messages: ": "Número de mensajes:", "Number of node(s)": "Número de nodo(s)", @@ -2655,7 +2659,7 @@ "Signatures": "Firmas", "Simple export (just the entity)": "Exportación simple (solamente la entidad)", "Simulate": "Simule", - "Simulated (emails)": "Simulado (emails)", + "Simulated emails (generated by AI)": "Correos electrónicos simulados (generados por IA)", "Simulation type": "Tipo de simulación", "Size": "Tamaño", "snort": "SNORT", @@ -2776,6 +2780,7 @@ "takedown_types": "tipos derribados", "tanium-signal": "Tanium Signal", "Target": "Objetivo", + "Targeted architecture": "Arquitectura objetivo", "Targeted by this actor": "Es objetivo de este actor", "Targeted by this intrusion set": "Es objetivo de este set de intrusión", "Targeted by this malware": "Es objetivo de este malware", @@ -2787,6 +2792,7 @@ "Targeted entity types": "Tipos de entidades atacadas", "Targeted in this campaign": "Es objetivo en esta campaña", "Targeted in this incident": "Es objetivo en este incidente", + "Targeted platforms": "Plataformas específicas", "Targeted sectors": "Sectores objetivo", "Targeting knowledge": "Conocimiento sobre los objetivos", "Targeting this country": "Atacando este país", @@ -2822,6 +2828,7 @@ "team": "Equipo organizado", "Technical": "Técnico", "Technical (payloads)": "Técnica (cargas útiles)", + "Technical (payloads) requires attack patterns in this entity.": "Técnica (cargas útiles) requiere patrones de ataque en esta entidad.", "Technical date": "Fecha técnica", "Technical elements (indicators & observables)": "Elementos técnicos (indicadores y observables)", "Techniques": "Técnicas", @@ -2853,6 +2860,7 @@ "the dedicated page": "la página dedicada", "The evaluation of the threat activity cannot be provided (lack of data).": "No se puede proporcionar la evaluación de la actividad de amenaza (falta de datos).", "The following groups require your attention:": "Los siguientes grupos requieren su atención:", + "The following TTPs are not covered in your OpenBAS catalog : ": "Los siguientes TTPs no están cubiertos en su catálogo OpenBAS :", "The importation of the file has been started": "La importación del fichero se ha iniciado", "The main object and the ... relationships/references linked to it will be deleted permanently.": "El objeto principal además de sus {count} relaciones/referencias serán eliminados definitivamente.", "The main object and the ... relationships/references linked to it will be restored.": "Se restaurará el objeto principal además de sus {count} relaciones/referencias.", @@ -2868,7 +2876,7 @@ "The retention policy will be applied on global workbenches (workbenches contained in": "La política de retención se aplicará a los bancos de trabajo globales (bancos de trabajo contenidos en", "The rule has been disabled, clean-up launched...": "La regla ha sido desactivada, limpieza lanzada...", "The rule has been enabled, rescan of platform data launched...": "La regla ha sido activada, reescaneo de los datos de la plataforma lanzado...", - "The scenario has been correctly generated in your OpenBAS platform": "El escenario se ha generado correctamente en su plataforma OpenBAS", + "The scenario has been correctly generated in your OpenBAS platform.": "El escenario se ha generado correctamente en su plataforma OpenBAS.", "The STIX ID has been removed": "El ID de STIX ha sido eliminado", "The tag has been added": "Se ha añadido la etiqueta", "The tag has been removed": "Se ha eliminado la etiqueta", diff --git a/opencti-platform/opencti-front/lang/front/fr.json b/opencti-platform/opencti-front/lang/front/fr.json index 33b3640a5bd3..fa05d3dc7607 100644 --- a/opencti-platform/opencti-front/lang/front/fr.json +++ b/opencti-platform/opencti-front/lang/front/fr.json @@ -30,12 +30,12 @@ "Access right": "Droit d'accès", "Access security activity": "Accéder à l'activité de sécurité", "Access stream directly in your browser": "Accédez au flux directement dans votre navigateur", + "Access this scenario": "Accéder à ce scénario", "Access to admin functionalities": "Accès aux fonctionnalités d'administration", "Access to collaborative creation": "Accéder à la création collaborative", "Access to file indexing": "Accès à l'indexation des fichiers", "Access to support": "Accéder au support", "Access to support data": "Accès aux données de support", - "Access to the scenario": "Accès au scénario", "Accessible for": "Accessible pour", "accidental": "Accidentel/Erreur", "Account expiration date": "Date d'expiration du compte", @@ -1490,6 +1490,7 @@ "In progress messages": "Messages en traitement", "In progress tasks": "Tâches en cours", "In progress works": "Exécutions en cours", + "In response, we have created placeholders for these TTPs.": "En réponse, nous avons créé des espaces réservés pour ces TTP.", "In this report, ": "Dans ce rapport, ", "In workbench": "Dans l'espace de travail", "Inactive": "Inactif", @@ -1579,7 +1580,9 @@ "INTERNAL_IMPORT_FILE": "Import de fichiers", "INTERNAL_INGESTION": "L'ingestion de données", "Interval": "Intervalle", - "Interval between injections (in minute)": "Intervalle entre les injections (en minute)", + "Interval between injections (in minutes)": "Intervalle entre les injections (en minutes)", + "Interval must be a positive number": "L'intervalle doit être un nombre positif", + "Interval must be an integer": "L'intervalle doit être un nombre entier", "Intrusion set": "Mode opératoire", "Intrusion Sets": "Modes Opératoires", "Intrusion sets": "Modes opératoires", @@ -1869,6 +1872,7 @@ "Minimum one event type": "Au moins un type d'événement", "Minimum one notifier": "Au moins un notifiant", "Minimum one organization": "Au moins une organisation", + "Minimum one platform": "Plate-forme minimale", "Minimum one recipient": "Au moins un destinataire", "Minimum one trigger": "Au moins un trigger", "MinIO": "MinIO", @@ -2031,7 +2035,7 @@ "Number of entities": "Nombre d'entités", "Number of errors": "Nombre d'erreurs", "Number of history entries": "Nombre d'entrées dans l'historique", - "Number of injects by attack pattern": "Nombre d'injections par modèle d'attaque", + "Number of injects generated by attack pattern and platform": "Nombre d'injections générées par le modèle d'attaque et la plateforme", "Number of lowercase chars must be greater or equals to": "Le nombre de caractères minuscules doit être supérieur ou égal à", "Number of messages: ": "Nombre de messages :", "Number of node(s)": "Nombre de nœuds", @@ -2655,7 +2659,7 @@ "Signatures": "Signatures", "Simple export (just the entity)": "Export simple (seulement l'entité)", "Simulate": "Simuler", - "Simulated (emails)": "Simulé (emails)", + "Simulated emails (generated by AI)": "Courriels simulés (générés par l'IA)", "Simulation type": "Type de simulation", "Size": "Taille", "snort": "SNORT", @@ -2776,6 +2780,7 @@ "takedown_types": "types de retraits", "tanium-signal": "Tanium Signal", "Target": "Cible", + "Targeted architecture": "Architecture ciblée", "Targeted by this actor": "Ciblé par cet acteur", "Targeted by this intrusion set": "Ciblé par ce mode opératoire", "Targeted by this malware": "Ciblé par ce code", @@ -2787,6 +2792,7 @@ "Targeted entity types": "Types d'entités ciblées", "Targeted in this campaign": "Ciblé dans cette campagne", "Targeted in this incident": "Ciblé dans cet incident", + "Targeted platforms": "Plateformes ciblées", "Targeted sectors": "Secteurs ciblés", "Targeting knowledge": "Connaissance du ciblage", "Targeting this country": "Ciblant ce pays", @@ -2822,6 +2828,7 @@ "team": "Equipe organisée", "Technical": "Technique", "Technical (payloads)": "Technique (charges utiles)", + "Technical (payloads) requires attack patterns in this entity.": "Le volet technique (charges utiles) nécessite des schémas d'attaque dans cette entité.", "Technical date": "Date technique", "Technical elements (indicators & observables)": "Eléments techniques (indicateurs & observables)", "Techniques": "Techniques", @@ -2853,6 +2860,7 @@ "the dedicated page": "la page dédiée", "The evaluation of the threat activity cannot be provided (lack of data).": "L'évaluation de l'activité de la menace ne peut être fournie (manque de données).", "The following groups require your attention:": "Les groupes suivants requièrent votre attention :", + "The following TTPs are not covered in your OpenBAS catalog : ": "Les TTP suivantes ne sont pas couvertes par votre catalogue OpenBAS :", "The importation of the file has been started": "L'importation du fichier a été lancée", "The main object and the ... relationships/references linked to it will be deleted permanently.": "L'objet principal ainsi que les {count} relations/références qui lui sont liées seront définitivement supprimés.", "The main object and the ... relationships/references linked to it will be restored.": "L'objet principal ainsi que les {count} relations/références qui lui sont liées seront restaurés.", @@ -2868,7 +2876,7 @@ "The retention policy will be applied on global workbenches (workbenches contained in": "La politique de conservation sera appliquée sur les postes de travail globaux (postes de travail contenus dans", "The rule has been disabled, clean-up launched...": "La règle a été déséactivée, purge lancée...", "The rule has been enabled, rescan of platform data launched...": "La règle a été activée, re-scan des données de la plateforme lancé...", - "The scenario has been correctly generated in your OpenBAS platform": "Le scénario a été correctement généré dans votre plateforme OpenBAS", + "The scenario has been correctly generated in your OpenBAS platform.": "Le scénario a été correctement généré dans votre plateforme OpenBAS.", "The STIX ID has been removed": "L'ID STIX a été supprimé", "The tag has been added": "La balise a été ajoutée", "The tag has been removed": "La balise a été supprimée", diff --git a/opencti-platform/opencti-front/lang/front/ja.json b/opencti-platform/opencti-front/lang/front/ja.json index bcc79b7cbe08..eba12bcc598d 100644 --- a/opencti-platform/opencti-front/lang/front/ja.json +++ b/opencti-platform/opencti-front/lang/front/ja.json @@ -30,12 +30,12 @@ "Access right": "アクセス権", "Access security activity": "セキュリティ活動にアクセス", "Access stream directly in your browser": "ブラウザで直接ストリームにアクセスする", + "Access this scenario": "このシナリオにアクセスする", "Access to admin functionalities": "管理機能へのアクセス", "Access to collaborative creation": "共同作成にアクセス", "Access to file indexing": "ファイルインデックスへのアクセス", "Access to support": "サポートにアクセス", "Access to support data": "サポートデータへのアクセス", - "Access to the scenario": "シナリオへのアクセス", "Accessible for": "アクセス可能", "accidental": "偶然/ミス", "Account expiration date": "アカウントの有効期限", @@ -1490,6 +1490,7 @@ "In progress messages": "処理中のメッセージ", "In progress tasks": "進行中のタスク", "In progress works": "進行中の作業", + "In response, we have created placeholders for these TTPs.": "これを受けて、我々はこれらのTTPのプレースホルダーを作成した。", "In this report, ": "このレポートでは、", "In workbench": "作業台にて", "Inactive": "非活性", @@ -1579,7 +1580,9 @@ "INTERNAL_IMPORT_FILE": "ファイルインポート", "INTERNAL_INGESTION": "データの取り込み", "Interval": "インターバル", - "Interval between injections (in minute)": "注入間隔(分)", + "Interval between injections (in minutes)": "注射の間隔(分)", + "Interval must be a positive number": "間隔は正の数でなければならない", + "Interval must be an integer": "間隔は整数でなければならない", "Intrusion set": "侵入セット", "Intrusion Sets": "侵入セット", "Intrusion sets": "侵入セット", @@ -1869,6 +1872,7 @@ "Minimum one event type": "最低1つのイベントタイプ", "Minimum one notifier": "最低1人の通知者", "Minimum one organization": "少なくとも 1 つの組織", + "Minimum one platform": "最低1つのプラットフォーム", "Minimum one recipient": "1人以上の受信者", "Minimum one trigger": "最小 1 つのトリガー", "MinIO": "MinIO", @@ -2031,7 +2035,7 @@ "Number of entities": "エンティティ数", "Number of errors": "エラー数", "Number of history entries": "履歴エントリ数", - "Number of injects by attack pattern": "攻撃パターン別インジェクト数", + "Number of injects generated by attack pattern and platform": "攻撃パターンとプラットフォームによって生成されたインジェクトの数", "Number of lowercase chars must be greater or equals to": "小文字の数は次の値以上でなければなりません", "Number of messages: ": "メッセージ数:", "Number of node(s)": "ノード数", @@ -2655,7 +2659,7 @@ "Signatures": "シグネチャ", "Simple export (just the entity)": "エンティティのみ出力", "Simulate": "シミュレート", - "Simulated (emails)": "シミュレーション(メール)", + "Simulated emails (generated by AI)": "模擬メール(AIが生成)", "Simulation type": "シミュレーションタイプ", "Size": "サイズ", "snort": "SNORT", @@ -2776,6 +2780,7 @@ "takedown_types": "テイクダウンの種類", "tanium-signal": "Taniumシグナル", "Target": "ターゲット", + "Targeted architecture": "標的型アーキテクチャ", "Targeted by this actor": "この脅威アクターの標的", "Targeted by this intrusion set": "この侵入セットの標的", "Targeted by this malware": "このマルウェアの標的", @@ -2787,6 +2792,7 @@ "Targeted entity types": "標的となったエンティティ種別", "Targeted in this campaign": "このキャンペーンの標的", "Targeted in this incident": "このインシデントの標的", + "Targeted platforms": "ターゲット・プラットフォーム", "Targeted sectors": "標的セクター", "Targeting knowledge": "ターゲットに関するナレッジ", "Targeting this country": "この国を標的にするもの", @@ -2822,6 +2828,7 @@ "team": "組織的なチーム", "Technical": "テクニカル", "Technical (payloads)": "テクニカル(ペイロード)", + "Technical (payloads) requires attack patterns in this entity.": "技術的(ペイロード)には、このエンティティの攻撃パターンが必要である。", "Technical date": "技術的な日時", "Technical elements (indicators & observables)": "技術的要素(インジケータと観測結果)", "Techniques": "技術", @@ -2853,6 +2860,7 @@ "the dedicated page": "専用ページ", "The evaluation of the threat activity cannot be provided (lack of data).": "脅威活動の評価が提供できない(データ不足)。", "The following groups require your attention:": "以下のグループに注目してほしい:", + "The following TTPs are not covered in your OpenBAS catalog : ": "以下の TTP は、OpenBAS のカタログではカバーされていません:", "The importation of the file has been started": "ファイルのインポートが開始されました", "The main object and the ... relationships/references linked to it will be deleted permanently.": "メインオブジェクトとそれにリンクされた {count} リレーションシップ/参照は永久に削除されます。", "The main object and the ... relationships/references linked to it will be restored.": "メインオブジェクトとそれにリンクされた{count}リレーションシップ/参照がリストアされます。", @@ -2868,7 +2876,7 @@ "The retention policy will be applied on global workbenches (workbenches contained in": "に含まれるワークベンチ)に適用されます。", "The rule has been disabled, clean-up launched...": "ルールは無効化され、クリーンアップが開始されました...", "The rule has been enabled, rescan of platform data launched...": "ルールが有効化され、プラットフォームデータの再スキャンが開始されました...", - "The scenario has been correctly generated in your OpenBAS platform": "シナリオはOpenBASプラットフォームで正しく生成されました。", + "The scenario has been correctly generated in your OpenBAS platform.": "シナリオは、OpenBAS プラットフォームで正しく生成されています。", "The STIX ID has been removed": "STIX ID が削除されました", "The tag has been added": "タグが追加されました", "The tag has been removed": "タグは削除されました", diff --git a/opencti-platform/opencti-front/lang/front/ko.json b/opencti-platform/opencti-front/lang/front/ko.json index d92b8721816c..1ccbe46dd765 100644 --- a/opencti-platform/opencti-front/lang/front/ko.json +++ b/opencti-platform/opencti-front/lang/front/ko.json @@ -30,12 +30,12 @@ "Access right": "접근 권한", "Access security activity": "보안 활동 액세스", "Access stream directly in your browser": "브라우저에서 스트림을 직접 액세스", + "Access this scenario": "이 시나리오에 액세스", "Access to admin functionalities": "관리자 기능에 액세스", "Access to collaborative creation": "공동 작업 생성에 대한 액세스", "Access to file indexing": "파일 인덱싱에 액세스", "Access to support": "지원 액세스", "Access to support data": "지원 데이터에 대한 액세스", - "Access to the scenario": "시나리오에 대한 접근", "Accessible for": "접근 가능", "accidental": "우발적/실수", "Account expiration date": "계정 만료일", @@ -1490,6 +1490,7 @@ "In progress messages": "진행 중인 메시지", "In progress tasks": "진행 중인 작업", "In progress works": "진행 중인 작업", + "In response, we have created placeholders for these TTPs.": "이에 따라 이러한 TTP에 대한 자리 표시자를 만들었습니다.", "In this report, ": "이 보고서에서, ", "In workbench": "작업대에서", "Inactive": "비활성", @@ -1579,7 +1580,9 @@ "INTERNAL_IMPORT_FILE": "파일 가져오기", "INTERNAL_INGESTION": "데이터 수집", "Interval": "간격", - "Interval between injections (in minute)": "주입 간격 (분 단위)", + "Interval between injections (in minutes)": "주입 간격(분)", + "Interval must be a positive number": "간격은 양수여야 합니다", + "Interval must be an integer": "간격은 정수여야 합니다", "Intrusion set": "침입 세트", "Intrusion Sets": "침입 세트", "Intrusion sets": "침입 세트", @@ -1869,6 +1872,7 @@ "Minimum one event type": "최소한의 하나의 이벤트 유형", "Minimum one notifier": "최소한의 하나의 알림자", "Minimum one organization": "최소 하나의 조직", + "Minimum one platform": "최소 하나의 플랫폼", "Minimum one recipient": "최소 한 명의 수신자", "Minimum one trigger": "최소한의 하나의 트리거", "MinIO": "MinIO", @@ -2031,7 +2035,7 @@ "Number of entities": "엔터티 수", "Number of errors": "오류 수", "Number of history entries": "히스토리 항목 수", - "Number of injects by attack pattern": "공격 패턴별 주입 수", + "Number of injects generated by attack pattern and platform": "공격 패턴과 플랫폼에 의해 생성된 인젝션 수", "Number of lowercase chars must be greater or equals to": "소문자 수는 더 크거나 같아야 합니다", "Number of messages: ": "메시지 수입니다:", "Number of node(s)": "노드 수", @@ -2655,7 +2659,7 @@ "Signatures": "서명", "Simple export (just the entity)": "간단한 내보내기 (엔터티만)", "Simulate": "시뮬레이션", - "Simulated (emails)": "시뮬레이션된 (이메일)", + "Simulated emails (generated by AI)": "시뮬레이션 이메일(AI로 생성)", "Simulation type": "시뮬레이션 유형", "Size": "크기", "snort": "SNORT", @@ -2776,6 +2780,7 @@ "takedown_types": "삭제 유형", "tanium-signal": "Tanium Signal", "Target": "목표", + "Targeted architecture": "표적 아키텍처", "Targeted by this actor": "이 행위자에 의해 표적됨", "Targeted by this intrusion set": "이 침입 세트에 의해 표적됨", "Targeted by this malware": "이 악성코드에 의해 표적됨", @@ -2787,6 +2792,7 @@ "Targeted entity types": "표적 엔터티 유형", "Targeted in this campaign": "이 캠페인에서 표적됨", "Targeted in this incident": "이 사건에서 표적됨", + "Targeted platforms": "타겟팅 플랫폼", "Targeted sectors": "표적 부문", "Targeting knowledge": "표적 지식", "Targeting this country": "이 국가를 표적으로 함", @@ -2822,6 +2828,7 @@ "team": "조직된 팀", "Technical": "기술적", "Technical (payloads)": "기술적 (페이로드)", + "Technical (payloads) requires attack patterns in this entity.": "기술(페이로드)은 이 엔티티의 공격 패턴을 필요로 합니다.", "Technical date": "기술적 날짜", "Technical elements (indicators & observables)": "기술적 요소 (인디케이터 및 관찰 가능)", "Techniques": "기법", @@ -2853,6 +2860,7 @@ "the dedicated page": "전용 페이지", "The evaluation of the threat activity cannot be provided (lack of data).": "위협 활동에 대한 평가를 제공할 수 없음(데이터 부족).", "The following groups require your attention:": "다음 그룹에 주의가 필요합니다:", + "The following TTPs are not covered in your OpenBAS catalog : ": "다음 TTP는 OpenBAS 카탈로그에서 다루지 않습니다:", "The importation of the file has been started": "파일 가져오기가 시작되었습니다", "The main object and the ... relationships/references linked to it will be deleted permanently.": "주 객체와 해당 객체와 연결된 {count} 관계/참조가 영구적으로 삭제됩니다.", "The main object and the ... relationships/references linked to it will be restored.": "주 객체와 해당 객체와 연결된 {count} 관계/참조가 복원됩니다.", @@ -2868,7 +2876,7 @@ "The retention policy will be applied on global workbenches (workbenches contained in": "에 포함된 파일)에 적용됩니다", "The rule has been disabled, clean-up launched...": "규칙이 비활성화되었습니다, 정리 시작...", "The rule has been enabled, rescan of platform data launched...": "규칙이 활성화되었습니다, 플랫폼 데이터 다시 스캔 시작...", - "The scenario has been correctly generated in your OpenBAS platform": "시나리오가 OpenBAS 플랫폼에서 올바르게 생성되었습니다", + "The scenario has been correctly generated in your OpenBAS platform.": "시나리오가 OpenBAS 플랫폼에서 올바르게 생성되었습니다.", "The STIX ID has been removed": "STIX ID가 제거되었습니다", "The tag has been added": "태그가 추가되었습니다", "The tag has been removed": "태그가 제거되었습니다", diff --git a/opencti-platform/opencti-front/lang/front/zh.json b/opencti-platform/opencti-front/lang/front/zh.json index 8e844ca306e7..3823f5678a71 100644 --- a/opencti-platform/opencti-front/lang/front/zh.json +++ b/opencti-platform/opencti-front/lang/front/zh.json @@ -30,12 +30,12 @@ "Access right": "访问权限", "Access security activity": "访问安全活动", "Access stream directly in your browser": "直接在浏览器中访问流", + "Access this scenario": "访问此方案", "Access to admin functionalities": "访问管理功能", "Access to collaborative creation": "访问协作创建", "Access to file indexing": "访问文件索引", "Access to support": "访问支持", "Access to support data": "访问支持数据", - "Access to the scenario": "进入场景", "Accessible for": "适用于", "accidental": "意外", "Account expiration date": "账户到期日期", @@ -1490,6 +1490,7 @@ "In progress messages": "进行中的消息", "In progress tasks": "进行中的任务", "In progress works": "进行中的工作", + "In response, we have created placeholders for these TTPs.": "为此,我们为这些 TTP 创建了占位符。", "In this report, ": "在这份报告中,", "In workbench": "在工作台上", "Inactive": "不活跃", @@ -1579,7 +1580,9 @@ "INTERNAL_IMPORT_FILE": "导入文件", "INTERNAL_INGESTION": "数据摄取", "Interval": "时间间隔", - "Interval between injections (in minute)": "注射间隔时间(分钟)", + "Interval between injections (in minutes)": "注射间隔时间(分钟)", + "Interval must be a positive number": "间隔必须是正数", + "Interval must be an integer": "间隔必须是整数", "Intrusion set": "入侵集合", "Intrusion Sets": "入侵集合", "Intrusion sets": "入侵集合", @@ -1869,6 +1872,7 @@ "Minimum one event type": "最少一种事件类型", "Minimum one notifier": "最少一个通知者", "Minimum one organization": "该值必须大于或等于 1", + "Minimum one platform": "最少一个平台", "Minimum one recipient": "最少一个收件人", "Minimum one trigger": "最少一个触发器", "MinIO": "MinIO", @@ -2031,7 +2035,7 @@ "Number of entities": "实体数量", "Number of errors": "错误数量", "Number of history entries": "历史记录条数", - "Number of injects by attack pattern": "按攻击模式注入的次数", + "Number of injects generated by attack pattern and platform": "攻击模式和平台生成的注入次数", "Number of lowercase chars must be greater or equals to": "小写字符的数量必须大于或等于", "Number of messages: ": "信息数量", "Number of node(s)": "节点数量", @@ -2655,7 +2659,7 @@ "Signatures": "签名", "Simple export (just the entity)": "简单导出(仅实体)", "Simulate": "模拟", - "Simulated (emails)": "模拟(电子邮件)", + "Simulated emails (generated by AI)": "模拟电子邮件(由人工智能生成)", "Simulation type": "模拟类型", "Size": "大小", "snort": "SNORT", @@ -2776,6 +2780,7 @@ "takedown_types": "删除类型", "tanium-signal": "Tanium信号", "Target": "目标", + "Targeted architecture": "目标架构", "Targeted by this actor": "被此威胁主体针对", "Targeted by this intrusion set": "被此入侵集合针对", "Targeted by this malware": "被该恶意软件针对", @@ -2787,6 +2792,7 @@ "Targeted entity types": "目标的实体类型", "Targeted in this campaign": "被该攻击活动针对", "Targeted in this incident": "被该安全事件针对", + "Targeted platforms": "目标平台", "Targeted sectors": "目标部门", "Targeting knowledge": "针对知识", "Targeting this country": "针对此国家/地区", @@ -2822,6 +2828,7 @@ "team": "团队", "Technical": "技术", "Technical (payloads)": "技术(有效载荷)", + "Technical (payloads) requires attack patterns in this entity.": "技术(有效载荷)需要该实体中的攻击模式。", "Technical date": "技术日期", "Technical elements (indicators & observables)": "技术元素(攻击指标和可观测数据)", "Techniques": "技术", @@ -2853,6 +2860,7 @@ "the dedicated page": "专用页面", "The evaluation of the threat activity cannot be provided (lack of data).": "无法提供对威胁活动的评估(缺乏数据)。", "The following groups require your attention:": "请您关注以下群体:", + "The following TTPs are not covered in your OpenBAS catalog : ": "OpenBAS 目录中不包括以下 TTP:", "The importation of the file has been started": "已开始导入文件", "The main object and the ... relationships/references linked to it will be deleted permanently.": "将永久删除主对象及其链接的 {count} 关系/引用。", "The main object and the ... relationships/references linked to it will be restored.": "将还原主对象和与之关联的 {count} 关系/引用。", @@ -2868,7 +2876,7 @@ "The retention policy will be applied on global workbenches (workbenches contained in": "保留策略将应用于全局工作台(工作台包含在", "The rule has been disabled, clean-up launched...": "该规则已禁用,清理已启动", "The rule has been enabled, rescan of platform data launched...": "该规则已启用,平台数据的重新扫描已启动", - "The scenario has been correctly generated in your OpenBAS platform": "场景已在 OpenBAS 平台正确生成", + "The scenario has been correctly generated in your OpenBAS platform.": "场景已在 OpenBAS 平台中正确生成。", "The STIX ID has been removed": "STIX ID 已被删除", "The tag has been added": "标签已添加", "The tag has been removed": "标签已删除", diff --git a/opencti-platform/opencti-front/src/private/components/analyses/groupings/Root.tsx b/opencti-platform/opencti-front/src/private/components/analyses/groupings/Root.tsx index 8d51db23fb91..f0f0b7af7d4e 100644 --- a/opencti-platform/opencti-front/src/private/components/analyses/groupings/Root.tsx +++ b/opencti-platform/opencti-front/src/private/components/analyses/groupings/Root.tsx @@ -10,7 +10,7 @@ import Tabs from '@mui/material/Tabs'; import Tab from '@mui/material/Tab'; import { GraphQLSubscriptionConfig } from 'relay-runtime'; import { RootReportSubscription } from '@components/analyses/reports/__generated__/RootReportSubscription.graphql'; -import StixCoreObjectSimulationResult from '@components/common/stix_core_objects/StixCoreObjectSimulationResult'; +import StixCoreObjectSimulationResultContainer from '@components/common/stix_core_objects/StixCoreObjectSimulationResultContainer'; import Security from 'src/utils/Security'; import StixCoreObjectContentRoot from '@components/common/stix_core_objects/StixCoreObjectContentRoot'; import { QueryRenderer } from '../../../../relay/environment'; @@ -183,7 +183,7 @@ const RootGrouping = () => { /> {isOverview && ( - + )} diff --git a/opencti-platform/opencti-front/src/private/components/analyses/reports/Root.tsx b/opencti-platform/opencti-front/src/private/components/analyses/reports/Root.tsx index ec18279df985..cd2a2e75b427 100644 --- a/opencti-platform/opencti-front/src/private/components/analyses/reports/Root.tsx +++ b/opencti-platform/opencti-front/src/private/components/analyses/reports/Root.tsx @@ -12,7 +12,7 @@ import Tab from '@mui/material/Tab'; import StixCoreObjectContentRoot from '@components/common/stix_core_objects/StixCoreObjectContentRoot'; import Security from 'src/utils/Security'; import AIInsights from '@components/common/ai/AIInsights'; -import StixCoreObjectSimulationResult from '../../common/stix_core_objects/StixCoreObjectSimulationResult'; +import StixCoreObjectSimulationResultContainer from '../../common/stix_core_objects/StixCoreObjectSimulationResultContainer'; import { QueryRenderer } from '../../../../relay/environment'; import Report from './Report'; import { RootReportSubscription } from './__generated__/RootReportSubscription.graphql'; @@ -187,7 +187,7 @@ const RootReport = () => { {!isKnowledgeOrContent && (
- +
)} diff --git a/opencti-platform/opencti-front/src/private/components/arsenal/malwares/Root.tsx b/opencti-platform/opencti-front/src/private/components/arsenal/malwares/Root.tsx index cb52cd6afe22..bc8a0a4506c9 100644 --- a/opencti-platform/opencti-front/src/private/components/arsenal/malwares/Root.tsx +++ b/opencti-platform/opencti-front/src/private/components/arsenal/malwares/Root.tsx @@ -9,7 +9,7 @@ import { GraphQLSubscriptionConfig } from 'relay-runtime'; import useForceUpdate from '@components/common/bulk/useForceUpdate'; import AIInsights from '@components/common/ai/AIInsights'; import StixCoreObjectContentRoot from '../../common/stix_core_objects/StixCoreObjectContentRoot'; -import StixCoreObjectSimulationResult from '../../common/stix_core_objects/StixCoreObjectSimulationResult'; +import StixCoreObjectSimulationResultContainer from '../../common/stix_core_objects/StixCoreObjectSimulationResultContainer'; import Malware from './Malware'; import MalwareKnowledge from './MalwareKnowledge'; import StixDomainObjectHeader from '../../common/stix_domain_objects/StixDomainObjectHeader'; @@ -206,7 +206,7 @@ const RootMalware = ({ queryRef, malwareId }: RootMalwareProps) => {
- +
diff --git a/opencti-platform/opencti-front/src/private/components/cases/case_incidents/Root.tsx b/opencti-platform/opencti-front/src/private/components/cases/case_incidents/Root.tsx index 67e861478a0d..b29a110f6e08 100644 --- a/opencti-platform/opencti-front/src/private/components/cases/case_incidents/Root.tsx +++ b/opencti-platform/opencti-front/src/private/components/cases/case_incidents/Root.tsx @@ -9,7 +9,7 @@ import { GraphQLSubscriptionConfig } from 'relay-runtime'; import Box from '@mui/material/Box'; import Tabs from '@mui/material/Tabs'; import Tab from '@mui/material/Tab'; -import StixCoreObjectSimulationResult from '@components/common/stix_core_objects/StixCoreObjectSimulationResult'; +import StixCoreObjectSimulationResultContainer from '@components/common/stix_core_objects/StixCoreObjectSimulationResultContainer'; import StixCoreObjectContentRoot from '@components/common/stix_core_objects/StixCoreObjectContentRoot'; import Security from 'src/utils/Security'; import AIInsights from '@components/common/ai/AIInsights'; @@ -181,7 +181,7 @@ const RootCaseIncidentComponent = ({ queryRef, caseId }) => { {!isKnowledgeOrContent && (
- +
)} diff --git a/opencti-platform/opencti-front/src/private/components/common/stix_core_objects/StixCoreObjectSimulationResult.jsx b/opencti-platform/opencti-front/src/private/components/common/stix_core_objects/StixCoreObjectSimulationResult.jsx index 0943203c479b..45dea510c924 100644 --- a/opencti-platform/opencti-front/src/private/components/common/stix_core_objects/StixCoreObjectSimulationResult.jsx +++ b/opencti-platform/opencti-front/src/private/components/common/stix_core_objects/StixCoreObjectSimulationResult.jsx @@ -1,41 +1,94 @@ +import { Field, Form, Formik } from 'formik'; +import MenuItem from '@mui/material/MenuItem'; +import Alert from '@mui/material/Alert'; +import Button from '@mui/material/Button'; import React, { useState } from 'react'; -import { makeStyles, useTheme } from '@mui/styles'; -import { CheckOutlined, OpenInNewOutlined, SensorOccupiedOutlined, ShieldOutlined, TrackChangesOutlined, ErrorOutlined, LaunchOutlined } from '@mui/icons-material'; import Tooltip from '@mui/material/Tooltip'; -import Button from '@mui/material/Button'; -import FormControl from '@mui/material/FormControl'; -import InputLabel from '@mui/material/InputLabel'; -import Select from '@mui/material/Select'; -import MenuItem from '@mui/material/MenuItem'; -import TextField from '@mui/material/TextField'; -import Switch from '@mui/material/Switch'; -import FormControlLabel from '@mui/material/FormControlLabel'; +import { CheckOutlined, ErrorOutlined, LaunchOutlined, OpenInNewOutlined, SensorOccupiedOutlined, ShieldOutlined, TrackChangesOutlined } from '@mui/icons-material'; import Box from '@mui/material/Box'; -import { graphql } from 'react-relay'; -import DialogActions from '@mui/material/DialogActions'; -import Dialog from '@mui/material/Dialog'; -import DialogTitle from '@mui/material/DialogTitle'; -import DialogContent from '@mui/material/DialogContent'; import CircularProgress from '@mui/material/CircularProgress'; import Typography from '@mui/material/Typography'; import { Link } from 'react-router-dom'; -import Alert from '@mui/material/Alert'; +import Dialog from '@mui/material/Dialog'; +import DialogContent from '@mui/material/DialogContent'; +import DialogActions from '@mui/material/DialogActions'; +import DialogTitle from '@mui/material/DialogTitle'; +import { graphql, usePreloadedQuery } from 'react-relay'; +import * as Yup from 'yup'; +import { useTheme } from '@mui/styles'; +import makeStyles from '@mui/styles/makeStyles'; import Drawer from '../drawer/Drawer'; import Chart from '../charts/Chart'; -import { useFormatter } from '../../../../components/i18n'; +import EEChip from '../entreprise_edition/EEChip'; +import Transition from '../../../../components/Transition'; +import obasLight from '../../../../static/images/xtm/obas_light.png'; +import obasDark from '../../../../static/images/xtm/obas_dark.png'; import { donutChartOptions } from '../../../../utils/Charts'; import { extractSimpleError, fileUri, QueryRenderer } from '../../../../relay/environment'; -import obasDark from '../../../../static/images/xtm/obas_dark.png'; -import obasLight from '../../../../static/images/xtm/obas_light.png'; -import useGranted, { KNOWLEDGE_KNUPDATE } from '../../../../utils/hooks/useGranted'; +import TextField from '../../../../components/TextField'; +import AutocompleteField from '../../../../components/AutocompleteField'; import { fieldSpacingContainerStyle } from '../../../../utils/field'; +import SelectField from '../../../../components/fields/SelectField'; +import { useFormatter } from '../../../../components/i18n'; import useEnterpriseEdition from '../../../../utils/hooks/useEnterpriseEdition'; -import useAI from '../../../../utils/hooks/useAI'; +import useGranted, { KNOWLEDGE_KNUPDATE } from '../../../../utils/hooks/useGranted'; +import useApiMutation from '../../../../utils/hooks/useApiMutation'; import useFiltersState from '../../../../utils/filters/useFiltersState'; import { emptyFilterGroup } from '../../../../utils/filters/filtersUtils'; -import useApiMutation from '../../../../utils/hooks/useApiMutation'; -import Transition from '../../../../components/Transition'; import useXTM from '../../../../utils/hooks/useXTM'; +import useAI from '../../../../utils/hooks/useAI'; + +const stixCoreObjectSimulationResultObasStixCoreObjectSimulationsResultQuery = graphql` + query StixCoreObjectSimulationResultObasStixCoreObjectSimulationsResultQuery($id: ID!) { + obasStixCoreObjectSimulationsResult(id: $id) { + prevention { + unknown + success + failure + } + detection { + unknown + success + failure + } + human { + unknown + success + failure + } + } + } +`; + +const stixCoreObjectSimulationResultObasContainerGenerateScenarioWithInjectPlaceholdersMutation = graphql` + mutation StixCoreObjectSimulationResultObasContainerGenerateScenarioWithInjectPlaceholdersMutation($id: ID!, $simulationConfig: SimulationConfig, $filters: FilterGroup) { + obasContainerGenerateScenarioWithInjectPlaceholders(id: $id, simulationConfig: $simulationConfig, filters: $filters){ + urlResponse + attackPatternsNotAvailableInOpenBAS + hasInjectPlaceholders + } + } +`; + +const stixCoreObjectSimulationResultObasThreatGenerateScenarioWithInjectPlaceholdersMutation = graphql` + mutation StixCoreObjectSimulationResultObasThreatGenerateScenarioWithInjectPlaceholdersMutation($id: ID!, $simulationConfig: SimulationConfig, $filters: FilterGroup) { + obasThreatGenerateScenarioWithInjectPlaceholders(id: $id, simulationConfig: $simulationConfig, filters: $filters) { + urlResponse + attackPatternsNotAvailableInOpenBAS + hasInjectPlaceholders + } + } +`; + +const stixCoreObjectSimulationResultObasVictimGenerateScenarioWithInjectPlaceholdersMutation = graphql` + mutation StixCoreObjectSimulationResultObasVictimGenerateScenarioWithInjectPlaceholdersMutation($id: ID!, $simulationConfig: SimulationConfig, $filters: FilterGroup) { + obasVictimGenerateScenarioWithInjectPlaceholders(id: $id, simulationConfig: $simulationConfig, filters: $filters){ + urlResponse + attackPatternsNotAvailableInOpenBAS + hasInjectPlaceholders + } + } +`; const useStyles = makeStyles((theme) => ({ simulationResults: { @@ -73,69 +126,54 @@ const useStyles = makeStyles((theme) => ({ }, })); -const stixCoreObjectSimulationResultObasStixCoreObjectSimulationsResultQuery = graphql` - query StixCoreObjectSimulationResultObasStixCoreObjectSimulationsResultQuery($id: ID!) { - obasStixCoreObjectSimulationsResult(id: $id) { - prevention { - unknown - success - failure - } - detection { - unknown - success - failure - } - human { - unknown - success - failure - } - } - } -`; - -const stixCoreObjectSimulationResultObasContainerGenerateScenarioMutation = graphql` - mutation StixCoreObjectSimulationResultObasContainerGenerateScenarioMutation($id: ID!, $interval: Int, $selection: Selection, $simulationType: SimulationType, $useAI: Boolean, $filters: FilterGroup) { - obasContainerGenerateScenario(id: $id, interval: $interval, selection: $selection, simulationType: $simulationType, useAI: $useAI, filters: $filters) - } -`; - -const stixCoreObjectSimulationResultObasThreatGenerateScenarioMutation = graphql` - mutation StixCoreObjectSimulationResultObasThreatGenerateScenarioMutation($id: ID!, $interval: Int, $selection: Selection, $simulationType: SimulationType, $useAI: Boolean, $filters: FilterGroup) { - obasThreatGenerateScenario(id: $id, interval: $interval, selection: $selection, simulationType: $simulationType, useAI: $useAI, filters: $filters) - } -`; - -const stixCoreObjectSimulationResultObasVictimGenerateScenarioMutation = graphql` - mutation StixCoreObjectSimulationResultObasVictimGenerateScenarioMutation($id: ID!, $interval: Int, $selection: Selection, $simulationType: SimulationType, $useAI: Boolean, $filters: FilterGroup) { - obasVictimGenerateScenario(id: $id, interval: $interval, selection: $selection, simulationType: $simulationType, useAI: $useAI, filters: $filters) - } -`; - -const StixCoreObjectSimulationResult = ({ id, type }) => { - const theme = useTheme(); +const StixCoreObjectSimulationResult = ({ + id, + queryRef, + query, + type, + simulationType, + setSimulationType, +}) => { + const { t_i18n } = useFormatter(); const classes = useStyles(); - const [open, setOpen] = useState(false); - const [openCallToAction, setOpenCallToAction] = useState(false); + const theme = useTheme(); const isEnterpriseEdition = useEnterpriseEdition(); + const isGrantedToUpdate = useGranted([KNOWLEDGE_KNUPDATE]); const { enabled, configured } = useAI(); + const isSimulatedEmailsAvailable = enabled && configured && isEnterpriseEdition; + const { oBasConfigured, oBasDisableDisplay } = useXTM(); - const [simulationType, setSimulationType] = useState('technical'); + const [filters, helpers] = useFiltersState(emptyFilterGroup); + + const [open, setOpen] = useState(false); + const [openCallToAction, setOpenCallToAction] = useState(false); + const [platforms, setPlatforms] = useState([{ label: 'Windows', value: 'Windows' }]); + const [architecture, setArchitecture] = useState('x86_64'); const [selection, setSelection] = useState('random'); const [interval, setInterval] = useState(2); - const [useGenAI, setUseGenAI] = useState(false); const [isSubmitting, setIsSubmitting] = useState(false); const [result, setResult] = useState(null); const [resultError, setResultError] = useState(null); - const [filters, helpers] = useFiltersState(emptyFilterGroup); - const { t_i18n } = useFormatter(); - const isGrantedToUpdate = useGranted([KNOWLEDGE_KNUPDATE]); + + const attackPatterns = usePreloadedQuery(query, queryRef); + + // Check if there are attack patterns in the entity + const hasAttackPatterns = ( + (type === 'container' && attackPatterns?.stixCoreObject?.objects?.edges?.length > 0) + || (type === 'threat' && attackPatterns?.stixCoreRelationships?.edges?.length > 0) + ); + + const platformOptions = [ + { label: 'Windows', value: 'Windows' }, + { label: 'Linux', value: 'Linux' }, + { label: 'MacOS', value: 'MacOS' }, + ]; + + const opacity = (!hasAttackPatterns && simulationType) === 'technical' ? 0.38 : 1; const handleClose = () => { setSimulationType('technical'); setInterval(2); - setUseGenAI(false); helpers.handleClearAllFilters(); setOpen(false); }; @@ -146,26 +184,38 @@ const StixCoreObjectSimulationResult = ({ id, type }) => { handleClose(); }; - const [commitMutationGenerateContainer] = useApiMutation(stixCoreObjectSimulationResultObasContainerGenerateScenarioMutation); - const [commitMutationGenerateThreat] = useApiMutation(stixCoreObjectSimulationResultObasThreatGenerateScenarioMutation); - const [commitMutationGenerateVictim] = useApiMutation(stixCoreObjectSimulationResultObasVictimGenerateScenarioMutation); + const canGenerateScenario = () => { + return ( + (simulationType === 'technical' && hasAttackPatterns && platforms.length > 0 && architecture) + || (simulationType === 'simulated' && enabled && configured && isEnterpriseEdition) + || (simulationType === 'mixed' && ((enabled && configured && isEnterpriseEdition) && (hasAttackPatterns && platforms.length > 0 && architecture))) + ); + }; + + const [commitMutationGenerateContainer] = useApiMutation(stixCoreObjectSimulationResultObasContainerGenerateScenarioWithInjectPlaceholdersMutation); + const [commitMutationGenerateThreat] = useApiMutation(stixCoreObjectSimulationResultObasThreatGenerateScenarioWithInjectPlaceholdersMutation); + const [commitMutationGenerateVictim] = useApiMutation(stixCoreObjectSimulationResultObasVictimGenerateScenarioWithInjectPlaceholdersMutation); const handleGenerate = () => { setIsSubmitting(true); setOpen(false); + const selectedPlatforms = platforms.map((option) => option.value); switch (type) { case 'container': commitMutationGenerateContainer({ variables: { id, - interval, - selection, - simulationType, - useAI: useGenAI, + simulationConfig: { + interval, + selection, + simulationType, + platforms: selectedPlatforms, + architecture, + }, filters, }, onCompleted: (response) => { - setResult(response.obasContainerGenerateScenario); + setResult(response.obasContainerGenerateScenarioWithInjectPlaceholders); setIsSubmitting(false); handleClose(); }, @@ -180,10 +230,13 @@ const StixCoreObjectSimulationResult = ({ id, type }) => { commitMutationGenerateThreat({ variables: { id, - interval, - selection, - simulationType, - useAI: useGenAI, + simulationConfig: { + interval, + selection, + simulationType, + platforms: selectedPlatforms, + architecture, + }, filters, }, onCompleted: (response) => { @@ -202,10 +255,13 @@ const StixCoreObjectSimulationResult = ({ id, type }) => { commitMutationGenerateVictim({ variables: { id, - interval, - selection, - simulationType, - useAI: useGenAI, + simulationConfig: { + interval, + selection, + simulationType, + platforms: selectedPlatforms, + architecture, + }, filters, }, onCompleted: (response) => { @@ -224,6 +280,158 @@ const StixCoreObjectSimulationResult = ({ id, type }) => { // do nothing } }; + + const initialValues = { + simulationType, + platforms, + architecture, + interval, + selection, + }; + + const simulationGenerationValidator = () => { + const basicShape = { + simulationType: Yup.string().required(t_i18n('This field is required')), + interval: Yup.number().required(t_i18n('This field is required')).positive(t_i18n('Interval must be a positive number')).integer(t_i18n('Interval must be an integer')), + selection: Yup.string().required(t_i18n('This field is required')), + }; + if (simulationType === 'simulated') { + return Yup.object().shape({ + ...basicShape, + }); + } + // For technical type + const technicalShape = { + platforms: Yup.array().min(1, t_i18n('Minimum one platform')).required(t_i18n('This field is required')), + architecture: Yup.string().required(t_i18n('This field is required')), + }; + return Yup.object().shape({ ...basicShape, ...technicalShape }); + }; + + const renderForm = () => { + return ( + + {({ isValid, values }) => ( +
+
+ setSimulationType(newValue)} + containerstyle={{ width: '100%', marginTop: 20, opacity }} + > + + {t_i18n('Technical (payloads)')} + + + {t_i18n('Simulated emails (generated by AI)')} + + + {t_i18n('Mixed (both)')} + + +
+ {values.simulationType !== 'simulated' && ( + <> + {!hasAttackPatterns && ( + + {t_i18n('Technical (payloads) requires attack patterns in this entity.')} + + )} +
+ setPlatforms(newValue)} + renderOption={(props, option) => ( +
  • +
    {option.label ?? ''}
    +
  • + )} + disabled={!hasAttackPatterns} + /> +
    +
    + setArchitecture(newValue)} + containerstyle={{ width: '100%' }} + > + x86_64 + arm64 + +
    + + )} +
    + setInterval(parseInt(newValue, 10))} + /> +
    +
    + setSelection(newValue)} + containerstyle={{ width: '100%' }} + > + {t_i18n('One (random)')} + {t_i18n('Multiple (limited to 5)')} + +
    +
    + + +
    +
    + )} +
    + ); + }; + const renderCharts = () => { return ( { /> ); }; - const renderForm = () => { - return ( - <> - setInterval(Number.isNaN(parseInt(event.target.value, 10)) ? 1 : parseInt(event.target.value, 10))} - style={fieldSpacingContainerStyle} - /> - - {t_i18n('Number of injects by attack pattern')} - - - setUseGenAI(event.target.checked)} /> - } - /> - - {t_i18n('Simulation type')} - - -
    - - -
    - - ); - }; + const renderCooking = () => { return (
    @@ -440,29 +583,48 @@ const StixCoreObjectSimulationResult = ({ id, type }) => {
    ); }; + const renderResult = () => { return ( <> } severity="success"> - {t_i18n('The scenario has been correctly generated in your OpenBAS platform')} + {t_i18n('The scenario has been correctly generated in your OpenBAS platform.')} - - ); }; + const renderResultError = () => { return ( - <> - } severity="error"> - {resultError} - - + } severity="error"> + {resultError} + ); }; + return ( <> {!oBasDisableDisplay && ( diff --git a/opencti-platform/opencti-front/src/private/components/common/stix_core_objects/StixCoreObjectSimulationResultContainer.jsx b/opencti-platform/opencti-front/src/private/components/common/stix_core_objects/StixCoreObjectSimulationResultContainer.jsx new file mode 100644 index 000000000000..85f3a8e85ce2 --- /dev/null +++ b/opencti-platform/opencti-front/src/private/components/common/stix_core_objects/StixCoreObjectSimulationResultContainer.jsx @@ -0,0 +1,91 @@ +import React, { useState } from 'react'; +import { graphql } from 'react-relay'; +import useQueryLoading from '../../../../utils/hooks/useQueryLoading'; +import StixCoreObjectSimulationResult from './StixCoreObjectSimulationResult'; +import Loader, { LoaderVariant } from '../../../../components/Loader'; + +const StixCoreObjectSimulationResultAttackPatternsForContainersQuery = graphql` + query StixCoreObjectSimulationResultContainerAttackPatternsForContainersQuery($id: String!) { + stixCoreObject(id: $id) { + id + entity_type + ... on Container { + objects (types: ["Attack-Pattern"]){ + edges { + types + node { + ... on AttackPattern { + id + } + } + } + } + } + } + } +`; + +const stixCoreObjectSimulationResultAttackPatternsForThreatsQuery = graphql` + query StixCoreObjectSimulationResultContainerAttackPatternsForThreatsQuery($id: Any!) { + stixCoreRelationships(filters: { + mode: and, + filters: [ + { + key: "relationship_type", + values: ["uses"], + }, + { + key: "fromOrToId", + values: [$id], + }, + { + key: "elementWithTargetTypes", + values: ["Attack-Pattern"], + } + ], + filterGroups: [ + + ], + }) { + edges { + node { + id + } + } + } + } +`; + +const StixCoreObjectSimulationResultContainer = ({ id, type }) => { + const [simulationType, setSimulationType] = useState('technical'); + // Determine the query based on the type + let attackPatternsQuery; + if (type === 'container') { + attackPatternsQuery = StixCoreObjectSimulationResultAttackPatternsForContainersQuery; + } else if (type === 'threat') { + attackPatternsQuery = stixCoreObjectSimulationResultAttackPatternsForThreatsQuery; + } else { + throw new Error('Type of the simulation should be container or threat'); + } + + // Fetch the attackPatterns using the selected query + const attackPatternsQueryRef = useQueryLoading(attackPatternsQuery, { id }); + + return ( + <> + {attackPatternsQueryRef && ( + }> + + + )} + + ); +}; +export default StixCoreObjectSimulationResultContainer; diff --git a/opencti-platform/opencti-front/src/private/components/events/incidents/Root.tsx b/opencti-platform/opencti-front/src/private/components/events/incidents/Root.tsx index 73be4d747626..26929d7a4beb 100644 --- a/opencti-platform/opencti-front/src/private/components/events/incidents/Root.tsx +++ b/opencti-platform/opencti-front/src/private/components/events/incidents/Root.tsx @@ -8,7 +8,7 @@ import { GraphQLSubscriptionConfig } from 'relay-runtime'; import Box from '@mui/material/Box'; import Tabs from '@mui/material/Tabs'; import Tab from '@mui/material/Tab'; -import StixCoreObjectSimulationResult from '@components/common/stix_core_objects/StixCoreObjectSimulationResult'; +import StixCoreObjectSimulationResultContainer from '@components/common/stix_core_objects/StixCoreObjectSimulationResultContainer'; import StixCoreObjectContentRoot from '@components/common/stix_core_objects/StixCoreObjectContentRoot'; import Security from 'src/utils/Security'; import { KNOWLEDGE_KNUPDATE } from 'src/utils/hooks/useGranted'; @@ -199,7 +199,7 @@ const RootIncidentComponent = ({ queryRef }) => { /> {isOverview && ( - + )} diff --git a/opencti-platform/opencti-front/src/private/components/threats/campaigns/Root.tsx b/opencti-platform/opencti-front/src/private/components/threats/campaigns/Root.tsx index f14740232f80..84a2e0e1a1a1 100644 --- a/opencti-platform/opencti-front/src/private/components/threats/campaigns/Root.tsx +++ b/opencti-platform/opencti-front/src/private/components/threats/campaigns/Root.tsx @@ -10,7 +10,7 @@ import { RootCampaignSubscription } from '@components/threats/campaigns/__genera import useForceUpdate from '@components/common/bulk/useForceUpdate'; import AIInsights from '@components/common/ai/AIInsights'; import StixCoreObjectContentRoot from '../../common/stix_core_objects/StixCoreObjectContentRoot'; -import StixCoreObjectSimulationResult from '../../common/stix_core_objects/StixCoreObjectSimulationResult'; +import StixCoreObjectSimulationResultContainer from '../../common/stix_core_objects/StixCoreObjectSimulationResultContainer'; import Campaign from './Campaign'; import CampaignKnowledge from './CampaignKnowledge'; import StixDomainObjectHeader from '../../common/stix_domain_objects/StixDomainObjectHeader'; @@ -200,7 +200,7 @@ const RootCampaign = ({ campaignId, queryRef }: RootCampaignProps) => {
    - +
    diff --git a/opencti-platform/opencti-front/src/private/components/threats/intrusion_sets/Root.tsx b/opencti-platform/opencti-front/src/private/components/threats/intrusion_sets/Root.tsx index 7d1b9b6121d7..85031944a05b 100644 --- a/opencti-platform/opencti-front/src/private/components/threats/intrusion_sets/Root.tsx +++ b/opencti-platform/opencti-front/src/private/components/threats/intrusion_sets/Root.tsx @@ -9,7 +9,7 @@ import useQueryLoading from 'src/utils/hooks/useQueryLoading'; import useForceUpdate from '@components/common/bulk/useForceUpdate'; import AIInsights from '@components/common/ai/AIInsights'; import StixCoreObjectContentRoot from '../../common/stix_core_objects/StixCoreObjectContentRoot'; -import StixCoreObjectSimulationResult from '../../common/stix_core_objects/StixCoreObjectSimulationResult'; +import StixCoreObjectSimulationResultContainer from '../../common/stix_core_objects/StixCoreObjectSimulationResultContainer'; import IntrusionSet from './IntrusionSet'; import IntrusionSetKnowledge from './IntrusionSetKnowledge'; import StixDomainObjectHeader from '../../common/stix_domain_objects/StixDomainObjectHeader'; @@ -206,7 +206,7 @@ const RootIntrusionSet = ({ intrusionSetId, queryRef }: RootIntrusionSetProps) =
    - +
    diff --git a/opencti-platform/opencti-front/src/private/components/threats/threat_actors_group/Root.tsx b/opencti-platform/opencti-front/src/private/components/threats/threat_actors_group/Root.tsx index e062632c6359..fd7e96cb52b2 100644 --- a/opencti-platform/opencti-front/src/private/components/threats/threat_actors_group/Root.tsx +++ b/opencti-platform/opencti-front/src/private/components/threats/threat_actors_group/Root.tsx @@ -11,7 +11,7 @@ import { RootThreatActorsGroupSubscription } from '@components/threats/threat_ac import useForceUpdate from '@components/common/bulk/useForceUpdate'; import AIInsights from '@components/common/ai/AIInsights'; import StixCoreObjectContentRoot from '../../common/stix_core_objects/StixCoreObjectContentRoot'; -import StixCoreObjectSimulationResult from '../../common/stix_core_objects/StixCoreObjectSimulationResult'; +import StixCoreObjectSimulationResultContainer from '../../common/stix_core_objects/StixCoreObjectSimulationResultContainer'; import ThreatActorGroup from './ThreatActorGroup'; import ThreatActorGroupKnowledge from './ThreatActorGroupKnowledge'; import Loader, { LoaderVariant } from '../../../../components/Loader'; @@ -204,7 +204,7 @@ const RootThreatActorGroup = ({ queryRef, threatActorGroupId }: RootThreatActorG
    - +
    diff --git a/opencti-platform/opencti-front/src/private/components/threats/threat_actors_individual/Root.tsx b/opencti-platform/opencti-front/src/private/components/threats/threat_actors_individual/Root.tsx index 4c1fb81a6c73..9b79c1c1c26d 100644 --- a/opencti-platform/opencti-front/src/private/components/threats/threat_actors_individual/Root.tsx +++ b/opencti-platform/opencti-front/src/private/components/threats/threat_actors_individual/Root.tsx @@ -8,7 +8,7 @@ import Tab from '@mui/material/Tab'; import StixCoreObjectContentRoot from '@components/common/stix_core_objects/StixCoreObjectContentRoot'; import useForceUpdate from '@components/common/bulk/useForceUpdate'; import AIInsights from '@components/common/ai/AIInsights'; -import StixCoreObjectSimulationResult from '../../common/stix_core_objects/StixCoreObjectSimulationResult'; +import StixCoreObjectSimulationResultContainer from '../../common/stix_core_objects/StixCoreObjectSimulationResultContainer'; import ErrorNotFound from '../../../../components/ErrorNotFound'; import useQueryLoading from '../../../../utils/hooks/useQueryLoading'; import Loader, { LoaderVariant } from '../../../../components/Loader'; @@ -218,7 +218,7 @@ const RootThreatActorIndividualComponent = ({
    - +
    diff --git a/opencti-platform/opencti-front/src/schema/relay.schema.graphql b/opencti-platform/opencti-front/src/schema/relay.schema.graphql index a38ae8c95f8e..09ee2970ff27 100644 --- a/opencti-platform/opencti-front/src/schema/relay.schema.graphql +++ b/opencti-platform/opencti-front/src/schema/relay.schema.graphql @@ -9007,9 +9007,9 @@ type Mutation { aiChangeTone(id: ID!, content: String!, format: Format, tone: Tone): String aiSummarize(id: ID!, content: String!, format: Format): String aiExplain(id: ID!, content: String!): String - obasContainerGenerateScenario(id: ID!, interval: Int, selection: Selection, simulationType: SimulationType, useAI: Boolean, filters: FilterGroup): String - obasThreatGenerateScenario(id: ID!, interval: Int, selection: Selection, simulationType: SimulationType, useAI: Boolean, filters: FilterGroup): String - obasVictimGenerateScenario(id: ID!, interval: Int, selection: Selection, simulationType: SimulationType, useAI: Boolean, filters: FilterGroup): String + obasContainerGenerateScenarioWithInjectPlaceholders(id: ID!, simulationConfig: SimulationConfig, filters: FilterGroup): GenerationResponse + obasThreatGenerateScenarioWithInjectPlaceholders(id: ID!, simulationConfig: SimulationConfig, filters: FilterGroup): GenerationResponse + obasVictimGenerateScenarioWithInjectPlaceholders(id: ID!, simulationConfig: SimulationConfig, filters: FilterGroup): GenerationResponse deleteOperationRestore(id: ID!): ID deleteOperationConfirm(id: ID!): ID supportPackageAdd(input: SupportPackageAddInput!): SupportPackage @@ -12313,6 +12313,31 @@ enum SimulationType { mixed } +enum Platform { + Windows + Linux + MacOS +} + +enum Architecture { + x86_64 + arm64 +} + +input SimulationConfig { + interval: Int! + selection: Selection! + simulationType: SimulationType! + platforms: [Platform] + architecture: Architecture +} + +type GenerationResponse { + urlResponse: String + attackPatternsNotAvailableInOpenBAS: String + hasInjectPlaceholders: Boolean +} + type SimulationsResult { unknown: Int success: Int diff --git a/opencti-platform/opencti-graphql/src/database/xtm-obas.ts b/opencti-platform/opencti-graphql/src/database/xtm-obas.ts index fae83e653491..0fdbb108e3f2 100644 --- a/opencti-platform/opencti-graphql/src/database/xtm-obas.ts +++ b/opencti-platform/opencti-graphql/src/database/xtm-obas.ts @@ -1,7 +1,7 @@ import conf, { getBaseUrl, logApp } from '../config/conf'; import { type GetHttpClient, getHttpClient } from '../utils/http-client'; import type { Label } from '../generated/graphql'; -import { DatabaseError } from '../config/errors'; +import { DatabaseError, ResourceNotFoundError } from '../config/errors'; import { isEmptyField } from './utils'; import { ENTITY_TYPE_CAMPAIGN, ENTITY_TYPE_CONTAINER_REPORT, ENTITY_TYPE_INCIDENT, ENTITY_TYPE_INTRUSION_SET, ENTITY_TYPE_THREAT_ACTOR_GROUP } from '../schema/stixDomainObject'; import { ENTITY_TYPE_CONTAINER_CASE_INCIDENT } from '../modules/case/case-incident/case-incident-types'; @@ -46,11 +46,42 @@ export const getAttackPatterns = async () => { } }; -export const getInjectorContracts = async (attackPatternId: string) => { +export const searchInjectorContracts = async (attackPatternId: string, platforms: string[], architecture: string) => { const httpClient = buildXTmOpenBasHttpClient(); try { - const { data: injectorContracts } = await httpClient.get(`/attack_patterns/${attackPatternId}/injector_contracts`); - return injectorContracts; + const attackPatternFilter = { + key: 'injector_contract_attack_patterns', + mode: 'and', + operator: 'contains', + values: [attackPatternId], + }; + const platformFilter = { + key: 'injector_contract_platforms', + mode: 'and', + operator: 'contains', + values: platforms, + }; + const architectureFilter = { + key: 'injector_contract_arch', + mode: 'and', + operator: 'eq', + values: [architecture], + }; + const searchPaginationInput = { + filterGroup: { + filters: [ + attackPatternFilter, + architectureFilter, + platformFilter, + ], + mode: 'and', + }, + page: 0, + size: 100, + }; + + const { data: injectorContracts } = await httpClient.post('/injector_contracts/search', searchPaginationInput); + return injectorContracts.content; } catch (err) { throw DatabaseError('Error querying OpenBAS', { cause: err }); } @@ -124,7 +155,9 @@ export const createInjectInScenario = async ( title: string, dependsDuration: number, content: string | null, - tags: Label[] + tags: Label[], + enabled: boolean, + description: string, ) => { const httpClient = buildXTmOpenBasHttpClient(); try { @@ -143,6 +176,8 @@ export const createInjectInScenario = async ( inject_depends_duration: dependsDuration, inject_content: content, inject_tags: obasTagsIds, + inject_enabled: enabled, + inject_description: description, } ); return inject; @@ -194,7 +229,7 @@ export const getScenarioResult = async (id: string) => { human, }; } catch (err) { - logApp.debug('Scenario not found in OpenBAS', { err }); + logApp.debug(`[OPENCTI-MODULE][XTM] Scenario results not found in OpenBAS : ${id}`, ResourceNotFoundError({ reason: 'Scenario results not found in OpenBAS', doc_code: 'ELEMENT_NOT_FOUND' })); return noResult; } }; diff --git a/opencti-platform/opencti-graphql/src/generated/graphql.ts b/opencti-platform/opencti-graphql/src/generated/graphql.ts index ec872ea6b070..c9dc5b67de63 100644 --- a/opencti-platform/opencti-graphql/src/generated/graphql.ts +++ b/opencti-platform/opencti-graphql/src/generated/graphql.ts @@ -401,6 +401,11 @@ export type AppMemory = { used_heap_size?: Maybe; }; +export enum Architecture { + Arm64 = 'arm64', + X86_64 = 'x86_64' +} + export type Artifact = BasicObject & HashedObservable & StixCoreObject & StixCyberObservable & StixObject & { __typename?: 'Artifact'; cases?: Maybe; @@ -8290,6 +8295,13 @@ export enum Format { Text = 'text' } +export type GenerationResponse = { + __typename?: 'GenerationResponse'; + attackPatternsNotAvailableInOpenBAS?: Maybe; + hasInjectPlaceholders?: Maybe; + urlResponse?: Maybe; +}; + export type GetMetrics = { __typename?: 'GetMetrics'; total?: Maybe; @@ -13739,9 +13751,15 @@ export type Mutation = { notifierAdd?: Maybe; notifierDelete?: Maybe; notifierFieldPatch?: Maybe; + /** @deprecated [>=6.5 & <6.8]. Use `obasContainerGenerateScenarioWithInjectPlaceholders`. */ obasContainerGenerateScenario?: Maybe; + obasContainerGenerateScenarioWithInjectPlaceholders?: Maybe; + /** @deprecated [>=6.5 & <6.8]. Use `obasThreatGenerateScenarioWithInjectPlaceholders`. */ obasThreatGenerateScenario?: Maybe; + obasThreatGenerateScenarioWithInjectPlaceholders?: Maybe; + /** @deprecated [>=6.5 & <6.8]. Use `obasVictimGenerateScenarioWithInjectPlaceholders`. */ obasVictimGenerateScenario?: Maybe; + obasVictimGenerateScenarioWithInjectPlaceholders?: Maybe; observedDataAdd?: Maybe; observedDataEdit?: Maybe; opinionAdd?: Maybe; @@ -15011,6 +15029,13 @@ export type MutationObasContainerGenerateScenarioArgs = { }; +export type MutationObasContainerGenerateScenarioWithInjectPlaceholdersArgs = { + filters?: InputMaybe; + id: Scalars['ID']['input']; + simulationConfig?: InputMaybe; +}; + + export type MutationObasThreatGenerateScenarioArgs = { filters?: InputMaybe; id: Scalars['ID']['input']; @@ -15021,6 +15046,13 @@ export type MutationObasThreatGenerateScenarioArgs = { }; +export type MutationObasThreatGenerateScenarioWithInjectPlaceholdersArgs = { + filters?: InputMaybe; + id: Scalars['ID']['input']; + simulationConfig?: InputMaybe; +}; + + export type MutationObasVictimGenerateScenarioArgs = { filters?: InputMaybe; id: Scalars['ID']['input']; @@ -15031,6 +15063,13 @@ export type MutationObasVictimGenerateScenarioArgs = { }; +export type MutationObasVictimGenerateScenarioWithInjectPlaceholdersArgs = { + filters?: InputMaybe; + id: Scalars['ID']['input']; + simulationConfig?: InputMaybe; +}; + + export type MutationObservedDataAddArgs = { input: ObservedDataAddInput; }; @@ -18674,6 +18713,12 @@ export type PhoneNumberAddInput = { value?: InputMaybe; }; +export enum Platform { + Linux = 'Linux', + MacOs = 'MacOS', + Windows = 'Windows' +} + export type PlatformCriticalAlert = { __typename?: 'PlatformCriticalAlert'; details?: Maybe; @@ -23764,6 +23809,14 @@ export type SettingsMessageInput = { recipients?: InputMaybe>; }; +export type SimulationConfig = { + architecture?: InputMaybe; + interval: Scalars['Int']['input']; + platforms?: InputMaybe>>; + selection: Selection; + simulationType: SimulationType; +}; + export enum SimulationType { Mixed = 'mixed', Simulated = 'simulated', @@ -31021,6 +31074,7 @@ export type ResolversTypes = ResolversObject<{ AppDebugStatistics: ResolverTypeWrapper; AppInfo: ResolverTypeWrapper; AppMemory: ResolverTypeWrapper; + Architecture: Architecture; Artifact: ResolverTypeWrapper & { cases?: Maybe, connectors?: Maybe>>, containers?: Maybe, createdBy?: Maybe, exportFiles?: Maybe, externalReferences?: Maybe, groupings?: Maybe, importFiles?: Maybe, indicators?: Maybe, jobs?: Maybe>>, notes?: Maybe, objectLabel?: Maybe>, objectMarking?: Maybe>, objectOrganization?: Maybe>, observedData?: Maybe, opinions?: Maybe, pendingFiles?: Maybe, reports?: Maybe, stixCoreObjectsDistribution?: Maybe>>, stixCoreRelationships?: Maybe, stixCoreRelationshipsDistribution?: Maybe>>, x_opencti_inferences?: Maybe>> }>; ArtifactAddInput: ArtifactAddInput; Assignee: ResolverTypeWrapper; @@ -31300,6 +31354,7 @@ export type ResolversTypes = ResolversObject<{ FintelTemplateWidgetAddInput: FintelTemplateWidgetAddInput; Float: ResolverTypeWrapper; Format: Format; + GenerationResponse: ResolverTypeWrapper; GetMetrics: ResolverTypeWrapper; Group: ResolverTypeWrapper & { allowed_marking?: Maybe>, default_dashboard?: Maybe, default_marking?: Maybe>, max_shareable_marking: Array, members?: Maybe }>; GroupAddInput: GroupAddInput; @@ -31539,6 +31594,7 @@ export type ResolversTypes = ResolversObject<{ PersonaAddInput: PersonaAddInput; PhoneNumber: ResolverTypeWrapper & { cases?: Maybe, connectors?: Maybe>>, containers?: Maybe, createdBy?: Maybe, exportFiles?: Maybe, externalReferences?: Maybe, groupings?: Maybe, importFiles?: Maybe, indicators?: Maybe, jobs?: Maybe>>, notes?: Maybe, objectLabel?: Maybe>, objectMarking?: Maybe>, objectOrganization?: Maybe>, observedData?: Maybe, opinions?: Maybe, pendingFiles?: Maybe, reports?: Maybe, stixCoreObjectsDistribution?: Maybe>>, stixCoreRelationships?: Maybe, stixCoreRelationshipsDistribution?: Maybe>>, x_opencti_inferences?: Maybe>> }>; PhoneNumberAddInput: PhoneNumberAddInput; + Platform: Platform; PlatformCriticalAlert: ResolverTypeWrapper & { details?: Maybe }>; PlatformCriticalAlertDetails: ResolverTypeWrapper & { groups: Array }>; PlatformCriticalAlertType: PlatformCriticalAlertType; @@ -31631,6 +31687,7 @@ export type ResolversTypes = ResolversObject<{ SettingsEditMutations: ResolverTypeWrapper & { contextClean?: Maybe, contextPatch?: Maybe, deleteMessage?: Maybe, editMessage?: Maybe, fieldPatch?: Maybe }>; SettingsMessage: ResolverTypeWrapper & { recipients?: Maybe> }>; SettingsMessageInput: SettingsMessageInput; + SimulationConfig: SimulationConfig; SimulationType: SimulationType; SimulationsResult: ResolverTypeWrapper; Software: ResolverTypeWrapper & { cases?: Maybe, connectors?: Maybe>>, containers?: Maybe, createdBy?: Maybe, exportFiles?: Maybe, externalReferences?: Maybe, groupings?: Maybe, importFiles?: Maybe, indicators?: Maybe, jobs?: Maybe>>, notes?: Maybe, objectLabel?: Maybe>, objectMarking?: Maybe>, objectOrganization?: Maybe>, observedData?: Maybe, opinions?: Maybe, pendingFiles?: Maybe, reports?: Maybe, stixCoreObjectsDistribution?: Maybe>>, stixCoreRelationships?: Maybe, stixCoreRelationshipsDistribution?: Maybe>>, vulnerabilities?: Maybe, x_opencti_inferences?: Maybe>> }>; @@ -32126,6 +32183,7 @@ export type ResolversParentTypes = ResolversObject<{ FintelTemplateWidget: FintelTemplateWidget; FintelTemplateWidgetAddInput: FintelTemplateWidgetAddInput; Float: Scalars['Float']['output']; + GenerationResponse: GenerationResponse; GetMetrics: GetMetrics; Group: Omit & { allowed_marking?: Maybe>, default_dashboard?: Maybe, default_marking?: Maybe>, max_shareable_marking: Array, members?: Maybe }; GroupAddInput: GroupAddInput; @@ -32411,6 +32469,7 @@ export type ResolversParentTypes = ResolversObject<{ SettingsEditMutations: Omit & { contextClean?: Maybe, contextPatch?: Maybe, deleteMessage?: Maybe, editMessage?: Maybe, fieldPatch?: Maybe }; SettingsMessage: Omit & { recipients?: Maybe> }; SettingsMessageInput: SettingsMessageInput; + SimulationConfig: SimulationConfig; SimulationsResult: SimulationsResult; Software: Omit & { cases?: Maybe, connectors?: Maybe>>, containers?: Maybe, createdBy?: Maybe, exportFiles?: Maybe, externalReferences?: Maybe, groupings?: Maybe, importFiles?: Maybe, indicators?: Maybe, jobs?: Maybe>>, notes?: Maybe, objectLabel?: Maybe>, objectMarking?: Maybe>, objectOrganization?: Maybe>, observedData?: Maybe, opinions?: Maybe, pendingFiles?: Maybe, reports?: Maybe, stixCoreObjectsDistribution?: Maybe>>, stixCoreRelationships?: Maybe, stixCoreRelationshipsDistribution?: Maybe>>, vulnerabilities?: Maybe, x_opencti_inferences?: Maybe>> }; SoftwareAddInput: SoftwareAddInput; @@ -35447,6 +35506,13 @@ export type FintelTemplateWidgetResolvers; }>; +export type GenerationResponseResolvers = ResolversObject<{ + attackPatternsNotAvailableInOpenBAS?: Resolver, ParentType, ContextType>; + hasInjectPlaceholders?: Resolver, ParentType, ContextType>; + urlResponse?: Resolver, ParentType, ContextType>; + __isTypeOf?: IsTypeOfResolverFn; +}>; + export type GetMetricsResolvers = ResolversObject<{ total?: Resolver, ParentType, ContextType>; __isTypeOf?: IsTypeOfResolverFn; @@ -37450,8 +37516,11 @@ export type MutationResolvers, ParentType, ContextType, RequireFields>; notifierFieldPatch?: Resolver, ParentType, ContextType, RequireFields>; obasContainerGenerateScenario?: Resolver, ParentType, ContextType, RequireFields>; + obasContainerGenerateScenarioWithInjectPlaceholders?: Resolver, ParentType, ContextType, RequireFields>; obasThreatGenerateScenario?: Resolver, ParentType, ContextType, RequireFields>; + obasThreatGenerateScenarioWithInjectPlaceholders?: Resolver, ParentType, ContextType, RequireFields>; obasVictimGenerateScenario?: Resolver, ParentType, ContextType, RequireFields>; + obasVictimGenerateScenarioWithInjectPlaceholders?: Resolver, ParentType, ContextType, RequireFields>; observedDataAdd?: Resolver, ParentType, ContextType, RequireFields>; observedDataEdit?: Resolver, ParentType, ContextType, RequireFields>; opinionAdd?: Resolver, ParentType, ContextType, RequireFields>; @@ -42219,6 +42288,7 @@ export type Resolvers = ResolversObject<{ FintelTemplateConnection?: FintelTemplateConnectionResolvers; FintelTemplateEdge?: FintelTemplateEdgeResolvers; FintelTemplateWidget?: FintelTemplateWidgetResolvers; + GenerationResponse?: GenerationResponseResolvers; GetMetrics?: GetMetricsResolvers; Group?: GroupResolvers; GroupConnection?: GroupConnectionResolvers; diff --git a/opencti-platform/opencti-graphql/src/modules/xtm/deprecated/xtm-deprecated.ts b/opencti-platform/opencti-graphql/src/modules/xtm/deprecated/xtm-deprecated.ts new file mode 100644 index 000000000000..27ece4162d9e --- /dev/null +++ b/opencti-platform/opencti-graphql/src/modules/xtm/deprecated/xtm-deprecated.ts @@ -0,0 +1,8 @@ +import { registerGraphqlSchema } from '../../../graphql/schema'; +import xtmTypeDefs from './xtm.graphql'; +import xtm_deprecated from './xtm-resolver'; + +registerGraphqlSchema({ + schema: xtmTypeDefs, + resolver: xtm_deprecated, +}); diff --git a/opencti-platform/opencti-graphql/src/modules/xtm/deprecated/xtm-domain.js b/opencti-platform/opencti-graphql/src/modules/xtm/deprecated/xtm-domain.js new file mode 100644 index 000000000000..37ab24e59974 --- /dev/null +++ b/opencti-platform/opencti-graphql/src/modules/xtm/deprecated/xtm-domain.js @@ -0,0 +1,87 @@ +// region [>=6.5 & <6.8] +import { listAllToEntitiesThroughRelations, storeLoadById } from '../../../database/middleware-loader'; +import { ABSTRACT_STIX_DOMAIN_OBJECT, ENTITY_TYPE_CONTAINER, ENTITY_TYPE_IDENTITY } from '../../../schema/general'; +import { RELATION_CREATED_BY, RELATION_OBJECT, RELATION_OBJECT_LABEL } from '../../../schema/stixRefRelationship'; +import { + ENTITY_TYPE_ATTACK_PATTERN, + ENTITY_TYPE_CAMPAIGN, + ENTITY_TYPE_INCIDENT, + ENTITY_TYPE_INTRUSION_SET, + ENTITY_TYPE_THREAT_ACTOR_GROUP +} from '../../../schema/stixDomainObject'; +import { ENTITY_TYPE_LABEL } from '../../../schema/stixMetaObject'; +import { RELATION_TARGETS, RELATION_USES } from '../../../schema/stixCoreRelationship'; +import { ENTITY_TYPE_THREAT_ACTOR_INDIVIDUAL } from '../../threatActorIndividual/threatActorIndividual-types'; +import { getDraftContext } from '../../../utils/draftContext'; +import { UnsupportedError } from '../../../config/errors'; +import { generateOpenBasScenarioWithInjectPlaceholders } from '../xtm-domain'; +import { checkEnterpriseEdition } from '../../../enterprise-edition/ee'; + +/** @deprecated [>=6.5 & <6.8]. Use `generateOpenBasScenarioWithInjectPlaceholders */ +export const generateOpenBasScenario = async (context, user, stixCoreObject, attackPatterns, labels, author, simulationType, interval, selection) => { + const response = await generateOpenBasScenarioWithInjectPlaceholders(context, user, stixCoreObject, attackPatterns, labels, author, { interval, selection, simulationType }); + return response.urlResponse; +}; + +/** @deprecated [>=6.5 & <6.8]. Use `generateContainerScenarioWithInjectPlaceholders */ +export const generateContainerScenario = async (context, user, args) => { + if (getDraftContext(context, user)) { + throw UnsupportedError('Cannot generate scenario in draft'); + } + const { id, interval, selection, simulationType = 'technical', useAI = false } = args; + if (useAI || simulationType !== 'technical') { + await checkEnterpriseEdition(context); + } + const container = await storeLoadById(context, user, id, ENTITY_TYPE_CONTAINER); + const author = await listAllToEntitiesThroughRelations(context, user, id, RELATION_CREATED_BY, [ENTITY_TYPE_IDENTITY]); + const labels = await listAllToEntitiesThroughRelations(context, user, id, RELATION_OBJECT_LABEL, [ENTITY_TYPE_LABEL]); + const attackPatterns = await listAllToEntitiesThroughRelations(context, user, id, RELATION_OBJECT, [ENTITY_TYPE_ATTACK_PATTERN]); + return generateOpenBasScenario(context, user, container, attackPatterns, labels, (author && author.length > 0 ? author.at(0) : 'Unknown'), simulationType, interval, selection); +}; + +/** @deprecated [>=6.5 & <6.8]. Use `generateThreatScenarioWithInjectPlaceholders */ +export const generateThreatScenario = async (context, user, args) => { + if (getDraftContext(context, user)) { + throw UnsupportedError('Cannot generate scenario in draft'); + } + const { id, interval, selection, simulationType = 'technical', useAI = false } = args; + if (useAI || simulationType !== 'technical') { + await checkEnterpriseEdition(context); + } + const stixCoreObject = await storeLoadById(context, user, id, ABSTRACT_STIX_DOMAIN_OBJECT); + const labels = await listAllToEntitiesThroughRelations(context, user, id, RELATION_OBJECT_LABEL, [ENTITY_TYPE_LABEL]); + const author = await listAllToEntitiesThroughRelations(context, user, id, RELATION_CREATED_BY, [ENTITY_TYPE_IDENTITY]); + const attackPatterns = await listAllToEntitiesThroughRelations(context, user, id, RELATION_USES, [ENTITY_TYPE_ATTACK_PATTERN]); + return generateOpenBasScenario(context, user, stixCoreObject, attackPatterns, labels, (author && author.length > 0 ? author.at(0) : 'Unknown'), simulationType, interval, selection); +}; + +/** @deprecated [>=6.5 & <6.8]. Use `generateVictimScenarioWithInjectPlaceholders */ +export const generateVictimScenario = async (context, user, args) => { + if (getDraftContext(context, user)) { + throw UnsupportedError('Cannot generate scenario in draft'); + } + const { id, interval, selection, simulationType = 'technical', useAI = false } = args; + if (useAI || simulationType !== 'technical') { + await checkEnterpriseEdition(context); + } + const stixCoreObject = await storeLoadById(context, user, id, ABSTRACT_STIX_DOMAIN_OBJECT); + const labels = await listAllToEntitiesThroughRelations(context, user, id, RELATION_OBJECT_LABEL, [ENTITY_TYPE_LABEL]); + const author = await listAllToEntitiesThroughRelations(context, user, id, RELATION_CREATED_BY, [ENTITY_TYPE_IDENTITY]); + const threats = await listAllToEntitiesThroughRelations( + context, + user, + id, + RELATION_TARGETS, + [ + ENTITY_TYPE_THREAT_ACTOR_GROUP, + ENTITY_TYPE_THREAT_ACTOR_INDIVIDUAL, + ENTITY_TYPE_INTRUSION_SET, + ENTITY_TYPE_CAMPAIGN, + ENTITY_TYPE_INCIDENT + ] + ); + const threatsIds = threats.map((n) => n.id); + const attackPatterns = await listAllToEntitiesThroughRelations(context, user, threatsIds, RELATION_USES, [ENTITY_TYPE_ATTACK_PATTERN]); + return generateOpenBasScenario(context, user, stixCoreObject, attackPatterns, labels, (author && author.length > 0 ? author.at(0) : 'Unknown'), simulationType, interval, selection); +}; +// endregion diff --git a/opencti-platform/opencti-graphql/src/modules/xtm/deprecated/xtm-resolver.ts b/opencti-platform/opencti-graphql/src/modules/xtm/deprecated/xtm-resolver.ts new file mode 100644 index 000000000000..f0b8b860a9f5 --- /dev/null +++ b/opencti-platform/opencti-graphql/src/modules/xtm/deprecated/xtm-resolver.ts @@ -0,0 +1,12 @@ +import type { Resolvers } from '../../../generated/graphql'; +import { generateContainerScenario, generateThreatScenario, generateVictimScenario } from './xtm-domain'; + +const aiResolvers_deprecated: Resolvers = { + Mutation: { + obasContainerGenerateScenario: (_, args, context) => generateContainerScenario(context, context.user, args), + obasThreatGenerateScenario: (_, args, context) => generateThreatScenario(context, context.user, args), + obasVictimGenerateScenario: (_, args, context) => generateVictimScenario(context, context.user, args), + }, +}; + +export default aiResolvers_deprecated; diff --git a/opencti-platform/opencti-graphql/src/modules/xtm/deprecated/xtm.graphql b/opencti-platform/opencti-graphql/src/modules/xtm/deprecated/xtm.graphql new file mode 100644 index 000000000000..78092e7abedd --- /dev/null +++ b/opencti-platform/opencti-graphql/src/modules/xtm/deprecated/xtm.graphql @@ -0,0 +1,5 @@ +type Mutation { + obasContainerGenerateScenario(id: ID!, interval: Int, selection: Selection, simulationType: SimulationType, useAI: Boolean, filters: FilterGroup): String @auth(for: [KNOWLEDGE_KNUPDATE])@deprecated(reason: "[>=6.5 & <6.8]. Use `obasContainerGenerateScenarioWithInjectPlaceholders`.") + obasThreatGenerateScenario(id: ID!, interval: Int, selection: Selection, simulationType: SimulationType, useAI: Boolean, filters: FilterGroup): String @auth(for: [KNOWLEDGE_KNUPDATE])@deprecated(reason: "[>=6.5 & <6.8]. Use `obasThreatGenerateScenarioWithInjectPlaceholders`.") + obasVictimGenerateScenario(id: ID!, interval: Int, selection: Selection, simulationType: SimulationType, useAI: Boolean, filters: FilterGroup): String @auth(for: [KNOWLEDGE_KNUPDATE])@deprecated(reason: "[>=6.5 & <6.8]. Use `obasVictimGenerateScenarioWithInjectPlaceholders`.") + } diff --git a/opencti-platform/opencti-graphql/src/modules/xtm/xtm-domain.js b/opencti-platform/opencti-graphql/src/modules/xtm/xtm-domain.js index ec6672125e33..0363551a1588 100644 --- a/opencti-platform/opencti-graphql/src/modules/xtm/xtm-domain.js +++ b/opencti-platform/opencti-graphql/src/modules/xtm/xtm-domain.js @@ -1,4 +1,3 @@ -import * as R from 'ramda'; import { listAllToEntitiesThroughRelations, storeLoadById } from '../../database/middleware-loader'; import { ABSTRACT_STIX_DOMAIN_OBJECT, buildRefRelationKey, ENTITY_TYPE_CONTAINER, ENTITY_TYPE_IDENTITY } from '../../schema/general'; import { RELATION_CREATED_BY, RELATION_OBJECT, RELATION_OBJECT_LABEL } from '../../schema/stixRefRelationship'; @@ -12,15 +11,14 @@ import { ENTITY_TYPE_INTRUSION_SET, ENTITY_TYPE_THREAT_ACTOR_GROUP } from '../../schema/stixDomainObject'; -import { UnsupportedError } from '../../config/errors'; import conf, { logApp } from '../../config/conf'; import { createInjectInScenario as obasCreateInjectInScenario, createScenario as obasCreateScenario, getAttackPatterns as obasGetAttackPatterns, - getInjectorContracts as obasGetInjectorContracts, getKillChainPhases as obasGetKillChainPhases, getScenarioResult as obasGetScenarioResult, + searchInjectorContracts as obasSearchInjectorContracts } from '../../database/xtm-obas'; import { isNotEmptyField } from '../../database/utils'; import { checkEnterpriseEdition } from '../../enterprise-edition/ee'; @@ -35,6 +33,9 @@ import { resolveFiles } from '../../utils/ai/dataResolutionHelpers'; const XTM_OPENBAS_URL = conf.get('xtm:openbas_url'); const SYSTEM_PROMPT = 'You are an assistant helping cybersecurity engineer to select attack simulation elements and actions based on the given threat intelligence information.'; const RESOLUTION_LIMIT = 50; +const obasManualContractId = 'd02e9132-b9d0-4daa-b3b1-4b9871f8472c'; +const obasEmailContractId = '2790bd39-37d4-4e39-be7e-53f3ca783f86'; +const obasInjectorType = 'openbas_email'; const getShuffledArr = (arr) => { const newArr = arr.slice(); @@ -67,7 +68,7 @@ export const resolveContent = async (context, user, stixCoreObject) => { files = await resolveFiles(context, user, stixCoreObject); } else { const containers = await listAllToEntitiesThroughRelations(context, user, stixCoreObject.id, RELATION_OBJECT, [ENTITY_TYPE_CONTAINER_REPORT]); - const allFiles = await Promise.all(R.take(15, containers).map((container) => resolveFiles(context, user, container))); + const allFiles = await Promise.all(containers.slice(0, 15)).map((container) => resolveFiles(context, user, container)); files = allFiles.flat(); names = containers.map((n) => n.name); descriptions = containers.map((n) => n.description); @@ -76,33 +77,34 @@ export const resolveContent = async (context, user, stixCoreObject) => { const result = [...names, ...descriptions, ...files.map((n) => n.content)].join(' '); return result; }; -const generateTechnicalAttackPattern = async (obasAttackPattern, selection, simulationType, obasScenario, dependsOnDuration, interval) => { - let dependsOnDurationLocal = dependsOnDuration; - const obasInjectorContracts = await obasGetInjectorContracts(obasAttackPattern.attack_pattern_id); - let finalObasInjectorContracts = R.take(5, getShuffledArr(obasInjectorContracts)); - if (selection === 'random') { - finalObasInjectorContracts = R.take(1, finalObasInjectorContracts); - } - if (simulationType === 'technical') { - // eslint-disable-next-line no-restricted-syntax - for (const finalObasInjectorContract of finalObasInjectorContracts) { - const obasInjectorContractContent = JSON.parse(finalObasInjectorContract.injector_contract_content); - const title = `[${obasAttackPattern.attack_pattern_external_id}] ${obasAttackPattern.attack_pattern_name} - ${finalObasInjectorContract.injector_contract_labels.en}`; - await obasCreateInjectInScenario( - obasScenario.scenario_id, - obasInjectorContractContent.config.type, - finalObasInjectorContract.injector_contract_id, - title, - dependsOnDurationLocal, - null, - [{ value: 'opencti', color: '#001bda' }, { value: 'technical', color: '#b9461a' }] - ); - dependsOnDurationLocal += (interval * 60); - } - } else { - // TODO - logApp.info(`[OPENCTI-MODULE][XTM] simulationType ${simulationType} not implemented yet.`); - } + +const generateTechnicalAttackPattern = async (obasAttackPattern, finalObasInjectorContract, scenarioId, dependsOnDuration) => { + const obasInjectorContractContent = JSON.parse(finalObasInjectorContract.injector_contract_content); + const title = `[${obasAttackPattern.attack_pattern_external_id}] ${obasAttackPattern.attack_pattern_name} - ${finalObasInjectorContract.injector_contract_labels.en}`; + await obasCreateInjectInScenario( + scenarioId, + obasInjectorContractContent.config.type, + finalObasInjectorContract.injector_contract_id, + title, + dependsOnDuration, + null, + [{ value: 'opencti', color: '#001bda' }, { value: 'technical', color: '#b9461a' }] + ); +}; + +const generatePlaceholder = async (externalId, platforms, architecture, scenarioId, dependsOnDuration) => { + const title = `[${externalId}] Placeholder - ${platforms.join(',')} ${architecture}`; + await obasCreateInjectInScenario( + scenarioId, + 'openbas_manual', + obasManualContractId, + title, + dependsOnDuration, + null, + [{ value: 'opencti', color: '#001bda' }, { value: 'technical', color: '#b9461a' }], + false, + `This placeholder is disabled because the TTP ${externalId} with platforms ${platforms.join(',')} and architecture ${architecture} is currently not covered. Please create the contracts for the missing TTPs`, + ); }; const generateAttackPatternEmail = async (obasAttackPattern, killChainPhaseName, killChainPhasesListOfNames, content, user, obasScenario, dependsOnDuration) => { @@ -142,8 +144,8 @@ const generateAttackPatternEmail = async (obasAttackPattern, killChainPhaseName, const titleIncidentResponse = `[${killChainPhaseName}] ${obasAttackPattern.attack_pattern_name} - Email to the incident response team`; await obasCreateInjectInScenario( obasScenario.scenario_id, - 'openbas_email', - '2790bd39-37d4-4e39-be7e-53f3ca783f86', + obasInjectorType, + obasEmailContractId, titleIncidentResponse, dependsOnDuration, { expectations: [], subject: responseIncidentResponseSubject.replace('Subject: ', '').replace('"', ''), body: responseIncidentResponse }, @@ -188,8 +190,8 @@ const generateAttackPatternEmailCiso = async (obasAttackPattern, killChainPhaseN await obasCreateInjectInScenario( obasScenario.scenario_id, - 'openbas_email', - '2790bd39-37d4-4e39-be7e-53f3ca783f86', + obasInjectorType, + obasEmailContractId, titleCiso, dependsOnDuration, { expectations: [], subject: responseCisoSubject.replace('Subject: ', '').replace('"', ''), body: responseCiso }, @@ -230,8 +232,8 @@ const generateKillChainEmailCiso = async (killChainPhaseName, killChainPhasesLis const titleCiso = `[${killChainPhaseName}] ${responseCisoSubject} - Email to the CISO`; await obasCreateInjectInScenario( obasScenario.scenario_id, - 'openbas_email', - '2790bd39-37d4-4e39-be7e-53f3ca783f86', + obasInjectorType, + obasEmailContractId, titleCiso, dependsOnDuration, { @@ -276,8 +278,8 @@ const generateKillChainEmail = async (killChainPhaseName, killChainPhasesListOfN const titleIncidentResponse = `[${killChainPhaseName}] ${responseIncidentResponseSubject} - Email to the incident response team`; await obasCreateInjectInScenario( obasScenario.scenario_id, - 'openbas_email', - '2790bd39-37d4-4e39-be7e-53f3ca783f86', + obasInjectorType, + obasEmailContractId, titleIncidentResponse, dependsOnDuration, { @@ -289,18 +291,35 @@ const generateKillChainEmail = async (killChainPhaseName, killChainPhasesListOfN ); }; -export const generateOpenBasScenario = async (context, user, stixCoreObject, attackPatterns, labels, author, simulationType, interval, selection, useAI) => { +export const generateOpenBasScenarioWithInjectPlaceholders = async ( + context, + user, + stixCoreObject, + attackPatterns, + labels, + author, + simulationConfig +) => { + const { interval, selection, simulationType = 'technical', platforms = ['Windows'], architecture = 'x86_64' } = simulationConfig; + // Initialize an array to collect attack patterns without contracts + let hasInjectPlaceholders = true; + const attackPatternsNotAvailableInOpenBAS = []; + + if (simulationType !== 'technical') { + await checkEnterpriseEdition(context); + } + const startingTime = new Date().getTime(); - logApp.info('[OPENCTI-MODULE][XTM] Starting to generate OBAS scenario', { useAI, simulationType }); + logApp.info('[OPENCTI-MODULE][XTM] Starting to generate OBAS scenario', { simulationType }); const content = await resolveContent(context, user, stixCoreObject); - const finalAttackPatterns = R.take(RESOLUTION_LIMIT, attackPatterns); + const finalAttackPatterns = attackPatterns.slice(0, RESOLUTION_LIMIT); // Create the scenario const name = `[${stixCoreObject.entity_type}] ${extractEntityRepresentativeName(stixCoreObject)}`; const description = extractRepresentativeDescription(stixCoreObject); const subtitle = `Based on cyber threat knowledge authored by ${author.name}`; - // call to obas + // call to OpenBAS const obasScenario = await obasCreateScenario( name, subtitle, @@ -312,30 +331,34 @@ export const generateOpenBasScenario = async (context, user, stixCoreObject, att ); // Get kill chain phases - const sortByPhaseOrder = R.sortBy(R.prop('phase_order')); - const obasKillChainPhases = await obasGetKillChainPhases(); // Why it's not called only inside if (attackPatterns.length === 0) ?? - const sortedObasKillChainPhases = sortByPhaseOrder(obasKillChainPhases); + const obasKillChainPhases = await obasGetKillChainPhases(); + const sortedObasKillChainPhases = obasKillChainPhases.sort((a, b) => a.phase_order - b.phase_order); const killChainPhasesListOfNames = sortedObasKillChainPhases.map((n) => n.phase_name).join(', '); - const indexedSortedObasKillChainPhase = R.indexBy(R.prop('phase_id'), sortedObasKillChainPhases); + const indexedSortedObasKillChainPhase = sortedObasKillChainPhases.reduce((acc, phase) => { + acc[phase.phase_id] = phase; + return acc; + }, {}); const createAndInjectScenarioPromises = []; let dependsOnDuration = 0; if (attackPatterns.length === 0) { - if (!useAI) { - throw UnsupportedError('No attack pattern associated to this entity. Please use AI to generate the scenario. This feature will be enhanced in the future to cover more types of entities.'); - } - // eslint-disable-next-line no-restricted-syntax - for (const obasKillChainPhase of sortedObasKillChainPhases) { - const killChainPhaseName = obasKillChainPhase.phase_name; - createAndInjectScenarioPromises.push(generateKillChainEmail(killChainPhaseName, killChainPhasesListOfNames, content, user, obasScenario, dependsOnDuration)); - dependsOnDuration += (interval * 60); - createAndInjectScenarioPromises.push(generateKillChainEmailCiso(killChainPhaseName, killChainPhasesListOfNames, content, user, obasScenario, dependsOnDuration)); - dependsOnDuration += (interval * 60); + if (simulationType === 'simulated') { + // eslint-disable-next-line no-restricted-syntax + for (const obasKillChainPhase of sortedObasKillChainPhases) { + const killChainPhaseName = obasKillChainPhase.phase_name; + createAndInjectScenarioPromises.push(generateKillChainEmail(killChainPhaseName, killChainPhasesListOfNames, content, user, obasScenario, dependsOnDuration)); + dependsOnDuration += (interval * 60); + createAndInjectScenarioPromises.push(generateKillChainEmailCiso(killChainPhaseName, killChainPhasesListOfNames, content, user, obasScenario, dependsOnDuration)); + dependsOnDuration += (interval * 60); + } + } else { + logApp.info('[OPENCTI-MODULE][XTM] No attack pattern associated to this entity. Please use AI to generate the scenario. This feature will be enhanced in the future to cover more types of entities.'); } } else { - logApp.debug('[OPENCTI-MODULE][XTM] attack pattern found, no generation of kill chain phase email'); + logApp.info('[OPENCTI-MODULE][XTM] Attack pattern found, no generation of kill chain phase email'); } + // Get contracts from OpenBAS related to found attack patterns // Get attack patterns @@ -347,87 +370,138 @@ export const generateOpenBasScenario = async (context, user, stixCoreObject, att // Keep only attack patterns matching the container ones const filteredObasAttackPatterns = obasAttackPatterns.filter((n) => attackPatternsMitreIds.includes(n.attack_pattern_external_id)); - // Enrich with the earliest kill chain phase - const enrichedFilteredObasAttackPatterns = filteredObasAttackPatterns.map( - (n) => R.assoc('attack_pattern_kill_chain_phase', sortByPhaseOrder(n.attack_pattern_kill_chain_phases.map((o) => indexedSortedObasKillChainPhase[o])).at(0), n) - ); - - // Sort attack pattern by kill chain phase - const sortByKillChainPhase = R.sortBy(R.path(['attack_pattern_kill_chain_phase', 'phase_order'])); - const sortedEnrichedFilteredObasAttackPatterns = sortByKillChainPhase(enrichedFilteredObasAttackPatterns); - - // Get the injector contracts - // eslint-disable-next-line no-restricted-syntax - for (const obasAttackPattern of sortedEnrichedFilteredObasAttackPatterns) { - const killChainPhaseName = obasAttackPattern.attack_pattern_kill_chain_phase.phase_name; - if (simulationType === 'simulated') { - createAndInjectScenarioPromises.push( - generateAttackPatternEmail(obasAttackPattern, killChainPhaseName, killChainPhasesListOfNames, content, user, obasScenario, dependsOnDuration) - ); - dependsOnDuration += (interval * 60); - createAndInjectScenarioPromises.push( - generateAttackPatternEmailCiso(obasAttackPattern, killChainPhaseName, killChainPhasesListOfNames, content, user, obasScenario, dependsOnDuration) - ); - dependsOnDuration += (interval * 60); + if (filteredObasAttackPatterns.length === 0) { + hasInjectPlaceholders = false; + let attackPatternsForPlaceholders = attackPatternsMitreIds; + if (attackPatternsMitreIds.length === 0) { + const attackPatternsNames = finalAttackPatterns.filter((n) => isNotEmptyField(n.name)).map((n) => n.name); + attackPatternsForPlaceholders = attackPatternsNames; + attackPatternsNotAvailableInOpenBAS.push(attackPatternsNames); + logApp.info(`[OPENCTI-MODULE][XTM] No external ID for : ${attackPatternsNames.join(', ')}`); } else { - createAndInjectScenarioPromises.push(generateTechnicalAttackPattern(obasAttackPattern, selection, simulationType, obasScenario, dependsOnDuration, interval)); - dependsOnDuration += (interval * 60); + attackPatternsNotAvailableInOpenBAS.push(attackPatternsMitreIds); + logApp.info(`[OPENCTI-MODULE][XTM] No attack patterns available on OpenBAS linked to these Mitre ids : ${attackPatternsMitreIds.join(', ')}`); } - } // end loop for - await Promise.all(createAndInjectScenarioPromises); - - const endingTime = new Date().getTime(); - const totalTime = endingTime - startingTime; - if (totalTime > 120000) { - logApp.warn('[OPENCTI-MODULE][XTM] Long scenario generation time', { - size: createAndInjectScenarioPromises.length, - took: totalTime, - useAI, - simulationType + if (simulationType !== 'simulated') { + hasInjectPlaceholders = true; + attackPatternsForPlaceholders.forEach((attackNotAvailable) => { + createAndInjectScenarioPromises.push(generatePlaceholder( + attackNotAvailable, + platforms, + architecture, + obasScenario.scenario_id, + dependsOnDuration + )); + dependsOnDuration += (interval * 60); + }); + } + } else { + // Enrich with the earliest kill chain phase + const enrichedFilteredObasAttackPatterns = filteredObasAttackPatterns.map((n) => { + const earliestKillChainPhase = n.attack_pattern_kill_chain_phases + .map((phaseId) => indexedSortedObasKillChainPhase[phaseId]) + .sort((a, b) => a.phase_order - b.phase_order)[0]; + return { ...n, attack_pattern_kill_chain_phase: earliestKillChainPhase }; }); + + // Sort attack pattern by kill chain phase + const sortedEnrichedFilteredObasAttackPatterns = enrichedFilteredObasAttackPatterns.sort((a, b) => { + return a.attack_pattern_kill_chain_phase.phase_order - b.attack_pattern_kill_chain_phase.phase_order; + }); + + // Get the injector contracts + // eslint-disable-next-line no-restricted-syntax + for (const obasAttackPattern of sortedEnrichedFilteredObasAttackPatterns) { + const killChainPhaseName = obasAttackPattern.attack_pattern_kill_chain_phase.phase_name; + if (simulationType === 'simulated') { + createAndInjectScenarioPromises.push( + generateAttackPatternEmail(obasAttackPattern, killChainPhaseName, killChainPhasesListOfNames, content, user, obasScenario, dependsOnDuration) + ); + dependsOnDuration += (interval * 60); + createAndInjectScenarioPromises.push( + generateAttackPatternEmailCiso(obasAttackPattern, killChainPhaseName, killChainPhasesListOfNames, content, user, obasScenario, dependsOnDuration) + ); + dependsOnDuration += (interval * 60); + } else { + const obasInjectorContracts = await obasSearchInjectorContracts(obasAttackPattern.attack_pattern_external_id, platforms, architecture); + if (obasInjectorContracts.length === 0) { + attackPatternsNotAvailableInOpenBAS.push(obasAttackPattern.attack_pattern_external_id); + logApp.info(`[OPENCTI-MODULE][XTM] No injector contracts available for this attack pattern ${obasAttackPattern.attack_pattern_external_id}`); + createAndInjectScenarioPromises.push(generatePlaceholder( + obasAttackPattern.attack_pattern_external_id, + platforms, + architecture, + obasScenario.scenario_id, + dependsOnDuration + )); + dependsOnDuration += (interval * 60); + } else { + let finalObasInjectorContracts = getShuffledArr(obasInjectorContracts).slice(0, 5); + if (selection === 'random') { + finalObasInjectorContracts = finalObasInjectorContracts.slice(0, 1); + } + if (simulationType === 'technical') { + // eslint-disable-next-line no-restricted-syntax + for (const finalObasInjectorContract of finalObasInjectorContracts) { + createAndInjectScenarioPromises.push(generateTechnicalAttackPattern(obasAttackPattern, finalObasInjectorContract, obasScenario.scenario_id, dependsOnDuration)); + dependsOnDuration += (interval * 60); + } + } else { + // TODO CASE Mixed (both) + logApp.info(`[OPENCTI-MODULE][XTM] simulationType ${simulationType} not implemented yet.`); + } + } + } + } // end loop for + + await Promise.all(createAndInjectScenarioPromises).catch((error) => logApp.error('[OPENCTI-MODULE][XTM] Error resolving promises', { error })); + + const endingTime = new Date().getTime(); + const totalTime = endingTime - startingTime; + if (totalTime > 120000) { + logApp.warn('[OPENCTI-MODULE][XTM] Long scenario generation time', { + size: createAndInjectScenarioPromises.length, + took: totalTime, + simulationType + }); + } + + logApp.info(`[OPENCTI-MODULE][XTM] Generating ${createAndInjectScenarioPromises.length} injects took ${totalTime} ms`, { simulationType }); } - logApp.info(`[OPENCTI-MODULE][XTM] Generating ${createAndInjectScenarioPromises.length} emails took ${totalTime} ms`, { useAI, simulationType }); - return `${XTM_OPENBAS_URL}/admin/scenarios/${obasScenario.scenario_id}/injects`; + + return { + urlResponse: `${XTM_OPENBAS_URL}/admin/scenarios/${obasScenario.scenario_id}/injects`, + attackPatternsNotAvailableInOpenBAS: attackPatternsNotAvailableInOpenBAS.join(','), + hasInjectPlaceholders, + }; }; -export const generateContainerScenario = async (context, user, args) => { - if (getDraftContext(context, user)) { - throw UnsupportedError('Cannot generate scenario in draft'); - } - const { id, interval, selection, simulationType = 'technical', useAI = false } = args; - if (useAI || simulationType !== 'technical') { - await checkEnterpriseEdition(context); - } +export const generateContainerScenarioWithInjectPlaceholders = async (context, user, args) => { + if (getDraftContext(context, user)) throw new Error('Cannot generate scenario in draft'); + const { id, simulationConfig } = args; + const container = await storeLoadById(context, user, id, ENTITY_TYPE_CONTAINER); const author = await listAllToEntitiesThroughRelations(context, user, id, RELATION_CREATED_BY, [ENTITY_TYPE_IDENTITY]); const labels = await listAllToEntitiesThroughRelations(context, user, id, RELATION_OBJECT_LABEL, [ENTITY_TYPE_LABEL]); const attackPatterns = await listAllToEntitiesThroughRelations(context, user, id, RELATION_OBJECT, [ENTITY_TYPE_ATTACK_PATTERN]); - return generateOpenBasScenario(context, user, container, attackPatterns, labels, (author && author.length > 0 ? author.at(0) : 'Unknown'), simulationType, interval, selection, useAI); + return generateOpenBasScenarioWithInjectPlaceholders(context, user, container, attackPatterns, labels, (author && author.length > 0 ? author.at(0) : 'Unknown'), simulationConfig); }; -export const generateThreatScenario = async (context, user, args) => { - if (getDraftContext(context, user)) { - throw UnsupportedError('Cannot generate scenario in draft'); - } - const { id, interval, selection, simulationType = 'technical', useAI = false } = args; - if (useAI || simulationType !== 'technical') { - await checkEnterpriseEdition(context); - } +export const generateThreatScenarioWithInjectPlaceholders = async (context, user, args) => { + if (getDraftContext(context, user)) throw new Error('Cannot generate scenario in draft'); + const { id, simulationConfig } = args; + const stixCoreObject = await storeLoadById(context, user, id, ABSTRACT_STIX_DOMAIN_OBJECT); const labels = await listAllToEntitiesThroughRelations(context, user, id, RELATION_OBJECT_LABEL, [ENTITY_TYPE_LABEL]); const author = await listAllToEntitiesThroughRelations(context, user, id, RELATION_CREATED_BY, [ENTITY_TYPE_IDENTITY]); const attackPatterns = await listAllToEntitiesThroughRelations(context, user, id, RELATION_USES, [ENTITY_TYPE_ATTACK_PATTERN]); - return generateOpenBasScenario(context, user, stixCoreObject, attackPatterns, labels, (author && author.length > 0 ? author.at(0) : 'Unknown'), simulationType, interval, selection, useAI); + return generateOpenBasScenarioWithInjectPlaceholders(context, user, stixCoreObject, attackPatterns, labels, (author && author.length > 0 ? author.at(0) : 'Unknown'), simulationConfig); }; -export const generateVictimScenario = async (context, user, args) => { - if (getDraftContext(context, user)) { - throw UnsupportedError('Cannot generate scenario in draft'); - } - const { id, interval, selection, simulationType = 'technical', useAI = false } = args; - if (useAI || simulationType !== 'technical') { - await checkEnterpriseEdition(context); - } +export const generateVictimScenarioWithInjectPlaceholders = async (context, user, args) => { + if (getDraftContext(context, user)) throw new Error('Cannot generate scenario in draft'); + const { id, simulationConfig } = args; + const stixCoreObject = await storeLoadById(context, user, id, ABSTRACT_STIX_DOMAIN_OBJECT); const labels = await listAllToEntitiesThroughRelations(context, user, id, RELATION_OBJECT_LABEL, [ENTITY_TYPE_LABEL]); const author = await listAllToEntitiesThroughRelations(context, user, id, RELATION_CREATED_BY, [ENTITY_TYPE_IDENTITY]); @@ -446,5 +520,5 @@ export const generateVictimScenario = async (context, user, args) => { ); const threatsIds = threats.map((n) => n.id); const attackPatterns = await listAllToEntitiesThroughRelations(context, user, threatsIds, RELATION_USES, [ENTITY_TYPE_ATTACK_PATTERN]); - return generateOpenBasScenario(context, user, stixCoreObject, attackPatterns, labels, (author && author.length > 0 ? author.at(0) : 'Unknown'), simulationType, interval, selection, useAI); + return generateOpenBasScenarioWithInjectPlaceholders(context, user, stixCoreObject, attackPatterns, labels, (author && author.length > 0 ? author.at(0) : 'Unknown'), simulationConfig); }; diff --git a/opencti-platform/opencti-graphql/src/modules/xtm/xtm-resolver.ts b/opencti-platform/opencti-graphql/src/modules/xtm/xtm-resolver.ts index d3c5bb851027..a673fee3d4e6 100644 --- a/opencti-platform/opencti-graphql/src/modules/xtm/xtm-resolver.ts +++ b/opencti-platform/opencti-graphql/src/modules/xtm/xtm-resolver.ts @@ -1,5 +1,11 @@ import type { Resolvers } from '../../generated/graphql'; -import { generateContainerScenario, generateThreatScenario, generateVictimScenario, scenarioElementsDistribution, stixCoreObjectSimulationsResult } from './xtm-domain'; +import { + generateContainerScenarioWithInjectPlaceholders, + generateThreatScenarioWithInjectPlaceholders, + generateVictimScenarioWithInjectPlaceholders, + scenarioElementsDistribution, + stixCoreObjectSimulationsResult +} from './xtm-domain'; const aiResolvers: Resolvers = { Query: { @@ -7,9 +13,9 @@ const aiResolvers: Resolvers = { obasScenarioElementsDistribution: (_, args, context) => scenarioElementsDistribution(context, context.user, args), }, Mutation: { - obasContainerGenerateScenario: (_, args, context) => generateContainerScenario(context, context.user, args), - obasThreatGenerateScenario: (_, args, context) => generateThreatScenario(context, context.user, args), - obasVictimGenerateScenario: (_, args, context) => generateVictimScenario(context, context.user, args), + obasContainerGenerateScenarioWithInjectPlaceholders: (_, args, context) => generateContainerScenarioWithInjectPlaceholders(context, context.user, args), + obasThreatGenerateScenarioWithInjectPlaceholders: (_, args, context) => generateThreatScenarioWithInjectPlaceholders(context, context.user, args), + obasVictimGenerateScenarioWithInjectPlaceholders: (_, args, context) => generateVictimScenarioWithInjectPlaceholders(context, context.user, args), }, }; diff --git a/opencti-platform/opencti-graphql/src/modules/xtm/xtm.graphql b/opencti-platform/opencti-graphql/src/modules/xtm/xtm.graphql index 1fbe442bf534..a47ae0be295c 100644 --- a/opencti-platform/opencti-graphql/src/modules/xtm/xtm.graphql +++ b/opencti-platform/opencti-graphql/src/modules/xtm/xtm.graphql @@ -15,6 +15,31 @@ enum SimulationType { mixed } +enum Platform { + Windows + Linux + MacOS +} + +enum Architecture { + x86_64 + arm64 +} + +input SimulationConfig { + interval: Int! + selection: Selection! + simulationType: SimulationType! + platforms: [Platform] + architecture: Architecture +} + +type GenerationResponse { + urlResponse: String + attackPatternsNotAvailableInOpenBAS: String + hasInjectPlaceholders: Boolean +} + type SimulationsResult { unknown: Int success: Int @@ -33,7 +58,7 @@ type Query { } type Mutation { - obasContainerGenerateScenario(id: ID!, interval: Int, selection: Selection, simulationType: SimulationType, useAI: Boolean, filters: FilterGroup): String @auth(for: [KNOWLEDGE_KNUPDATE]) - obasThreatGenerateScenario(id: ID!, interval: Int, selection: Selection, simulationType: SimulationType, useAI: Boolean, filters: FilterGroup): String @auth(for: [KNOWLEDGE_KNUPDATE]) - obasVictimGenerateScenario(id: ID!, interval: Int, selection: Selection, simulationType: SimulationType, useAI: Boolean, filters: FilterGroup): String @auth(for: [KNOWLEDGE_KNUPDATE]) + obasContainerGenerateScenarioWithInjectPlaceholders(id: ID!, simulationConfig: SimulationConfig, filters: FilterGroup): GenerationResponse @auth(for: [KNOWLEDGE_KNUPDATE]) + obasThreatGenerateScenarioWithInjectPlaceholders(id: ID!, simulationConfig: SimulationConfig, filters: FilterGroup): GenerationResponse @auth(for: [KNOWLEDGE_KNUPDATE]) + obasVictimGenerateScenarioWithInjectPlaceholders(id: ID!, simulationConfig: SimulationConfig, filters: FilterGroup): GenerationResponse @auth(for: [KNOWLEDGE_KNUPDATE]) }