From db260180eb45301515aca38d28dbd5eed3e9974f Mon Sep 17 00:00:00 2001 From: Stephanya Casanova Date: Thu, 5 Dec 2024 17:31:42 +0100 Subject: [PATCH 1/8] [frontend/backend] wip --- .../opencti-front/lang/front/de.json | 13 +- .../opencti-front/lang/front/en.json | 13 +- .../opencti-front/lang/front/es.json | 13 +- .../opencti-front/lang/front/fr.json | 13 +- .../opencti-front/lang/front/ja.json | 13 +- .../opencti-front/lang/front/ko.json | 13 +- .../opencti-front/lang/front/zh.json | 13 +- .../StixCoreObjectSimulationResult.jsx | 281 ++++++++++++++---- .../src/schema/relay.schema.graphql | 30 +- .../opencti-graphql/src/database/xtm-obas.ts | 41 ++- .../opencti-graphql/src/generated/graphql.ts | 65 ++-- .../src/modules/xtm/xtm.graphql | 29 +- 12 files changed, 428 insertions(+), 109 deletions(-) diff --git a/opencti-platform/opencti-front/lang/front/de.json b/opencti-platform/opencti-front/lang/front/de.json index 28bf4f61da39..4d263e215b70 100644 --- a/opencti-platform/opencti-front/lang/front/de.json +++ b/opencti-platform/opencti-front/lang/front/de.json @@ -1579,7 +1579,7 @@ "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)", "Intrusion set": "Intrusion set", "Intrusion Sets": "Intrusion Sets", "Intrusion sets": "Intrusion-Sets", @@ -2031,7 +2031,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 +2655,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 +2776,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 +2788,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 +2824,7 @@ "team": "Organisiertes Team", "Technical": "Technisch", "Technical (payloads)": "Technisch (Nutzlasten)", + "Technical (payloads) require 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 +2856,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 the Openbas catalog : ": "Die folgenden TTPs sind nicht im Openbas-Katalog 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 +2872,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", @@ -2917,6 +2921,7 @@ "This field must be >= 1": "Dieses Feld muss >= 1 sein", "This field must be a number": "Dieses Feld muss eine Zahl sein", "This field must only contain alphanumeric chars, dashes and space": "Dieses Feld darf nur alphanumerische Zeichen, Bindestriche und Leerzeichen enthalten", + "This field should not be empty": "Dieses Feld sollte nicht leer sein", "This file is not in the specified format": "Diese Datei hat nicht das angegebene Format", "This file is too large": "Diese Datei ist zu groß", "This filter contains imbricated filter groups, that are not fully supported yet in the platform display and can only be edited via the API. They might have been created via the API or a migration from a previous filter format. For your information, here is the content of the filter object: ": "Dieser Filter enthält ineinander verschachtelte Filtergruppen, die in der Plattformanzeige noch nicht vollständig unterstützt werden und nur über die API bearbeitet werden können. Sie können über die API oder eine Migration von einem früheren Filterformat erstellt worden sein. Zu Ihrer Information, hier ist der Inhalt des Filterobjekts:", diff --git a/opencti-platform/opencti-front/lang/front/en.json b/opencti-platform/opencti-front/lang/front/en.json index d0ef1a4e26b8..d6ecaf7b1d2f 100644 --- a/opencti-platform/opencti-front/lang/front/en.json +++ b/opencti-platform/opencti-front/lang/front/en.json @@ -1579,7 +1579,7 @@ "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)", "Intrusion set": "Intrusion set", "Intrusion Sets": "Intrusion Sets", "Intrusion sets": "Intrusion sets", @@ -2031,7 +2031,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 +2655,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 +2776,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 +2788,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 +2824,7 @@ "team": "Organized team", "Technical": "Technical", "Technical (payloads)": "Technical (payloads)", + "Technical (payloads) require attack patterns in this entity.": "Technical (payloads) require attack patterns in this entity.", "Technical date": "Technical date", "Technical elements (indicators & observables)": "Technical elements (indicators & observables)", "Techniques": "Techniques", @@ -2853,6 +2856,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 the Openbas catalog : ": "The following TTPs are not covered in the 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 +2872,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", @@ -2917,6 +2921,7 @@ "This field must be >= 1": "This field must be >= 1", "This field must be a number": "This field must be a number", "This field must only contain alphanumeric chars, dashes and space": "This field must only contain alphanumeric chars, dashes and space", + "This field should not be empty": "This field should not be empty", "This file is not in the specified format": "This file is not in the specified format", "This file is too large": "This file is too large", "This filter contains imbricated filter groups, that are not fully supported yet in the platform display and can only be edited via the API. They might have been created via the API or a migration from a previous filter format. For your information, here is the content of the filter object: ": "This filter contains imbricated filter groups, that are not fully supported yet in the platform display and can only be edited via the API. They might have been created via the API or a migration from a previous filter format. For your information, here is the content of the filter object: ", diff --git a/opencti-platform/opencti-front/lang/front/es.json b/opencti-platform/opencti-front/lang/front/es.json index 50dd59ae1dea..fb56aad1c415 100644 --- a/opencti-platform/opencti-front/lang/front/es.json +++ b/opencti-platform/opencti-front/lang/front/es.json @@ -1579,7 +1579,7 @@ "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)", "Intrusion set": "Set de intrusión", "Intrusion Sets": "Intrusion Sets", "Intrusion sets": "Sets de intrusión", @@ -2031,7 +2031,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 +2655,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 +2776,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 +2788,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 +2824,7 @@ "team": "Equipo organizado", "Technical": "Técnico", "Technical (payloads)": "Técnica (cargas útiles)", + "Technical (payloads) require attack patterns in this entity.": "Técnica (cargas útiles) requieren 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 +2856,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 the Openbas catalog : ": "Los siguientes TTPs no están cubiertos en el 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 +2872,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", @@ -2917,6 +2921,7 @@ "This field must be >= 1": "Este campo debe ser >= 1", "This field must be a number": "Este campo debe ser un número", "This field must only contain alphanumeric chars, dashes and space": "Este campo debe contener solamente caracteres alfanuméricos, guiones y espacios", + "This field should not be empty": "Este campo no debe estar vacío", "This file is not in the specified format": "Este archivo no tiene el formato especificado", "This file is too large": "Este archivo es demasiado grande", "This filter contains imbricated filter groups, that are not fully supported yet in the platform display and can only be edited via the API. They might have been created via the API or a migration from a previous filter format. For your information, here is the content of the filter object: ": "Este filtro contiene grupos de filtros imbricados, que aún no son completamente compatibles en la visualización de la plataforma y solo se pueden editar a través de la API. Es posible que se hayan creado a través de la API o una migración desde un formato de filtro anterior. Para tu información, aquí está el contenido del objeto de filtro:", diff --git a/opencti-platform/opencti-front/lang/front/fr.json b/opencti-platform/opencti-front/lang/front/fr.json index 33b3640a5bd3..9109cc3c5401 100644 --- a/opencti-platform/opencti-front/lang/front/fr.json +++ b/opencti-platform/opencti-front/lang/front/fr.json @@ -1579,7 +1579,7 @@ "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)", "Intrusion set": "Mode opératoire", "Intrusion Sets": "Modes Opératoires", "Intrusion sets": "Modes opératoires", @@ -2031,7 +2031,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 +2655,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 +2776,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 +2788,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 +2824,7 @@ "team": "Equipe organisée", "Technical": "Technique", "Technical (payloads)": "Technique (charges utiles)", + "Technical (payloads) require attack patterns in this entity.": "Les données techniques (charges utiles) requièrent 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 +2856,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 the Openbas catalog : ": "Les TTP suivantes ne sont pas couvertes par le 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 +2872,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", @@ -2917,6 +2921,7 @@ "This field must be >= 1": "Ce champ doit être >= 1", "This field must be a number": "Ce champ doit être un nombre", "This field must only contain alphanumeric chars, dashes and space": "Ce champ ne peut contenir que des caractères alphanumériques, des tirets et des espaces", + "This field should not be empty": "Ce champ ne doit pas être vide", "This file is not in the specified format": "Ce fichier n'est pas au format spécifié", "This file is too large": "Ce fichier est trop volumineux", "This filter contains imbricated filter groups, that are not fully supported yet in the platform display and can only be edited via the API. They might have been created via the API or a migration from a previous filter format. For your information, here is the content of the filter object: ": "Ce filtre contient des groupes de filtres imbriqués, qui ne sont pas encore totalement pris en charge dans l'affichage de la plateforme et ne peuvent être modifiés que via l'API. Ils peuvent avoir été créés via l'API ou lors d'une migration à partir d'un format de filtre précédent. Pour votre information, voici le contenu de l'objet de filtre:", diff --git a/opencti-platform/opencti-front/lang/front/ja.json b/opencti-platform/opencti-front/lang/front/ja.json index bcc79b7cbe08..c805fb882b24 100644 --- a/opencti-platform/opencti-front/lang/front/ja.json +++ b/opencti-platform/opencti-front/lang/front/ja.json @@ -1579,7 +1579,7 @@ "INTERNAL_IMPORT_FILE": "ファイルインポート", "INTERNAL_INGESTION": "データの取り込み", "Interval": "インターバル", - "Interval between injections (in minute)": "注入間隔(分)", + "Interval between injections (in minutes)": "注射の間隔(分)", "Intrusion set": "侵入セット", "Intrusion Sets": "侵入セット", "Intrusion sets": "侵入セット", @@ -2031,7 +2031,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 +2655,7 @@ "Signatures": "シグネチャ", "Simple export (just the entity)": "エンティティのみ出力", "Simulate": "シミュレート", - "Simulated (emails)": "シミュレーション(メール)", + "Simulated emails (generated by AI)": "模擬メール(AIが生成)", "Simulation type": "シミュレーションタイプ", "Size": "サイズ", "snort": "SNORT", @@ -2776,6 +2776,7 @@ "takedown_types": "テイクダウンの種類", "tanium-signal": "Taniumシグナル", "Target": "ターゲット", + "Targeted architecture": "標的型アーキテクチャ", "Targeted by this actor": "この脅威アクターの標的", "Targeted by this intrusion set": "この侵入セットの標的", "Targeted by this malware": "このマルウェアの標的", @@ -2787,6 +2788,7 @@ "Targeted entity types": "標的となったエンティティ種別", "Targeted in this campaign": "このキャンペーンの標的", "Targeted in this incident": "このインシデントの標的", + "Targeted platforms": "ターゲット・プラットフォーム", "Targeted sectors": "標的セクター", "Targeting knowledge": "ターゲットに関するナレッジ", "Targeting this country": "この国を標的にするもの", @@ -2822,6 +2824,7 @@ "team": "組織的なチーム", "Technical": "テクニカル", "Technical (payloads)": "テクニカル(ペイロード)", + "Technical (payloads) require attack patterns in this entity.": "技術的(ペイロード)には、このエンティティの攻撃パターンが必要である。", "Technical date": "技術的な日時", "Technical elements (indicators & observables)": "技術的要素(インジケータと観測結果)", "Techniques": "技術", @@ -2853,6 +2856,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 the 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 +2872,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": "タグは削除されました", @@ -2917,6 +2921,7 @@ "This field must be >= 1": "このフィールドは>= 1でなければならない", "This field must be a number": "このフィールドは数字でなければなりません", "This field must only contain alphanumeric chars, dashes and space": "このフィールドに入力可能な文字はアルファベット、数字、\"-\", 半角スペースのみです", + "This field should not be empty": "このフィールドは空であってはならない", "This file is not in the specified format": "このファイルは指定された形式ではありません", "This file is too large": "このファイルは大きすぎます", "This filter contains imbricated filter groups, that are not fully supported yet in the platform display and can only be edited via the API. They might have been created via the API or a migration from a previous filter format. For your information, here is the content of the filter object: ": "このフィルターには、プラットフォームの表示ではまだ完全にサポートされていない、入れ子になったフィルターグループが含まれており、API経由でのみ編集することができます。これらはAPI経由で作成されたか、以前のフィルターフォーマットからの移行で作成された可能性があります。フィルターオブジェクトの内容は次のとおりです", diff --git a/opencti-platform/opencti-front/lang/front/ko.json b/opencti-platform/opencti-front/lang/front/ko.json index d92b8721816c..fefcd9c981b5 100644 --- a/opencti-platform/opencti-front/lang/front/ko.json +++ b/opencti-platform/opencti-front/lang/front/ko.json @@ -1579,7 +1579,7 @@ "INTERNAL_IMPORT_FILE": "파일 가져오기", "INTERNAL_INGESTION": "데이터 수집", "Interval": "간격", - "Interval between injections (in minute)": "주입 간격 (분 단위)", + "Interval between injections (in minutes)": "주입 간격(분)", "Intrusion set": "침입 세트", "Intrusion Sets": "침입 세트", "Intrusion sets": "침입 세트", @@ -2031,7 +2031,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 +2655,7 @@ "Signatures": "서명", "Simple export (just the entity)": "간단한 내보내기 (엔터티만)", "Simulate": "시뮬레이션", - "Simulated (emails)": "시뮬레이션된 (이메일)", + "Simulated emails (generated by AI)": "시뮬레이션 이메일(AI로 생성)", "Simulation type": "시뮬레이션 유형", "Size": "크기", "snort": "SNORT", @@ -2776,6 +2776,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 +2788,7 @@ "Targeted entity types": "표적 엔터티 유형", "Targeted in this campaign": "이 캠페인에서 표적됨", "Targeted in this incident": "이 사건에서 표적됨", + "Targeted platforms": "타겟팅 플랫폼", "Targeted sectors": "표적 부문", "Targeting knowledge": "표적 지식", "Targeting this country": "이 국가를 표적으로 함", @@ -2822,6 +2824,7 @@ "team": "조직된 팀", "Technical": "기술적", "Technical (payloads)": "기술적 (페이로드)", + "Technical (payloads) require attack patterns in this entity.": "기술(페이로드)은 이 엔티티에 공격 패턴이 필요합니다.", "Technical date": "기술적 날짜", "Technical elements (indicators & observables)": "기술적 요소 (인디케이터 및 관찰 가능)", "Techniques": "기법", @@ -2853,6 +2856,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 the 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 +2872,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": "태그가 제거되었습니다", @@ -2917,6 +2921,7 @@ "This field must be >= 1": "이 필드는 &\\\\;= 1이어야 합니다", "This field must be a number": "이 필드는 숫자여야 합니다", "This field must only contain alphanumeric chars, dashes and space": "이 필드는 영숫자, 대시 및 공백만 포함해야 합니다", + "This field should not be empty": "이 필드는 비어 있으면 안 됩니다", "This file is not in the specified format": "이 파일은 지정된 형식이 아닙니다", "This file is too large": "이 파일은 너무 큽니다", "This filter contains imbricated filter groups, that are not fully supported yet in the platform display and can only be edited via the API. They might have been created via the API or a migration from a previous filter format. For your information, here is the content of the filter object: ": "이 필터에는 플랫폼 디스플레이에서 아직 완전히 지원되지 않으며 API를 통해서만 편집할 수 있는 중첩된 필터 그룹이 포함되어 있습니다. 이는 API를 통해 생성되었거나 이전 필터 형식에서 마이그레이션된 것일 수 있습니다. 참고로 여기에 필터 객체의 내용이 있습니다: ", diff --git a/opencti-platform/opencti-front/lang/front/zh.json b/opencti-platform/opencti-front/lang/front/zh.json index 8e844ca306e7..bdf6141883d2 100644 --- a/opencti-platform/opencti-front/lang/front/zh.json +++ b/opencti-platform/opencti-front/lang/front/zh.json @@ -1579,7 +1579,7 @@ "INTERNAL_IMPORT_FILE": "导入文件", "INTERNAL_INGESTION": "数据摄取", "Interval": "时间间隔", - "Interval between injections (in minute)": "注射间隔时间(分钟)", + "Interval between injections (in minutes)": "注射间隔时间(分钟)", "Intrusion set": "入侵集合", "Intrusion Sets": "入侵集合", "Intrusion sets": "入侵集合", @@ -2031,7 +2031,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 +2655,7 @@ "Signatures": "签名", "Simple export (just the entity)": "简单导出(仅实体)", "Simulate": "模拟", - "Simulated (emails)": "模拟(电子邮件)", + "Simulated emails (generated by AI)": "模拟电子邮件(由人工智能生成)", "Simulation type": "模拟类型", "Size": "大小", "snort": "SNORT", @@ -2776,6 +2776,7 @@ "takedown_types": "删除类型", "tanium-signal": "Tanium信号", "Target": "目标", + "Targeted architecture": "目标架构", "Targeted by this actor": "被此威胁主体针对", "Targeted by this intrusion set": "被此入侵集合针对", "Targeted by this malware": "被该恶意软件针对", @@ -2787,6 +2788,7 @@ "Targeted entity types": "目标的实体类型", "Targeted in this campaign": "被该攻击活动针对", "Targeted in this incident": "被该安全事件针对", + "Targeted platforms": "目标平台", "Targeted sectors": "目标部门", "Targeting knowledge": "针对知识", "Targeting this country": "针对此国家/地区", @@ -2822,6 +2824,7 @@ "team": "团队", "Technical": "技术", "Technical (payloads)": "技术(有效载荷)", + "Technical (payloads) require attack patterns in this entity.": "技术(有效载荷)需要该实体中的攻击模式。", "Technical date": "技术日期", "Technical elements (indicators & observables)": "技术元素(攻击指标和可观测数据)", "Techniques": "技术", @@ -2853,6 +2856,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 the 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 +2872,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": "标签已删除", @@ -2917,6 +2921,7 @@ "This field must be >= 1": "此字段必须为 >= 1", "This field must be a number": "该字段必须为数字", "This field must only contain alphanumeric chars, dashes and space": "此字段只能包含字母、数字、字符、下划线和空格", + "This field should not be empty": "该字段不应为空", "This file is not in the specified format": "该文件不是指定格式", "This file is too large": "该文件太大", "This filter contains imbricated filter groups, that are not fully supported yet in the platform display and can only be edited via the API. They might have been created via the API or a migration from a previous filter format. For your information, here is the content of the filter object: ": "这个过滤器含有嵌套的过滤器组,目前平台的显示还不完全支持,只能通过 API 进行编辑。它们可能是通过 API 创建的,或者是从之前的过滤器格式迁移过来的。为了供您参考,这里是过滤器对象的内容:", 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..8b409ad1a8cf 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,4 +1,4 @@ -import React, { useState } from 'react'; +import React, { useEffect, 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'; @@ -8,10 +8,8 @@ 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 Box from '@mui/material/Box'; -import { graphql } from 'react-relay'; +import { graphql, useLazyLoadQuery } from 'react-relay'; import DialogActions from '@mui/material/DialogActions'; import Dialog from '@mui/material/Dialog'; import DialogTitle from '@mui/material/DialogTitle'; @@ -20,6 +18,8 @@ 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 { Autocomplete } from '@mui/material'; +import EEChip from '../entreprise_edition/EEChip'; import Drawer from '../drawer/Drawer'; import Chart from '../charts/Chart'; import { useFormatter } from '../../../../components/i18n'; @@ -96,20 +96,81 @@ const stixCoreObjectSimulationResultObasStixCoreObjectSimulationsResultQuery = g `; 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) + mutation StixCoreObjectSimulationResultObasContainerGenerateScenarioMutation($id: ID!, $simulationConfig: SimulationConfig, $filters: FilterGroup) { + obasContainerGenerateScenario(id: $id, simulationConfig: $simulationConfig, filters: $filters){ + urlResponse + attackPatternsWithoutInjectorContracts + } } `; 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) + mutation StixCoreObjectSimulationResultObasThreatGenerateScenarioMutation($id: ID!, $simulationConfig: SimulationConfig, $filters: FilterGroup) { + obasThreatGenerateScenario(id: $id, simulationConfig: $simulationConfig, filters: $filters) { + urlResponse + attackPatternsWithoutInjectorContracts + } } `; 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) + mutation StixCoreObjectSimulationResultObasVictimGenerateScenarioMutation($id: ID!, $simulationConfig: SimulationConfig, $filters: FilterGroup) { + obasVictimGenerateScenario(id: $id, simulationConfig: $simulationConfig, filters: $filters){ + urlResponse + attackPatternsWithoutInjectorContracts + } + } +`; + +const StixCoreObjectSimulationResultAttackPatternsForContainersQuery = graphql` + query StixCoreObjectSimulationResultAttackPatternsForContainersQuery($id: String!) { + stixCoreObject(id: $id) { + id + entity_type + ... on Container { + objects (types: ["Attack-Pattern"]){ + edges { + types + node { + ... on AttackPattern { + id + } + } + } + } + } + } + } +`; + +const stixCoreObjectSimulationResultAttackPatternsForThreatsQuery = graphql` + query StixCoreObjectSimulationResultAttackPatternsForThreatsQuery($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 + } + } + } } `; @@ -118,24 +179,61 @@ const StixCoreObjectSimulationResult = ({ id, type }) => { const classes = useStyles(); const [open, setOpen] = useState(false); const [openCallToAction, setOpenCallToAction] = useState(false); + const { oBasConfigured, oBasDisableDisplay } = useXTM(); const isEnterpriseEdition = useEnterpriseEdition(); const { enabled, configured } = useAI(); - const { oBasConfigured, oBasDisableDisplay } = useXTM(); + const isSimulatedEmailsAvailable = enabled && configured && isEnterpriseEdition; const [simulationType, setSimulationType] = useState('technical'); + const [platforms, setPlatforms] = useState(['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 [platformError, setPlatformError] = useState(''); + + const platformOptions = [ + { label: 'Windows', value: 'Windows' }, + { label: 'Linux', value: 'Linux' }, + { label: 'MacOS', value: 'MacOS' }, + ]; + + // 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 attackPatterns = useLazyLoadQuery(attackPatternsQuery, { id }); + + // Check if there are attack patterns in the entity + let hasAttackPatterns = false; + if (type === 'container' && attackPatterns?.stixCoreObject?.objects?.edges?.length > 0) { + hasAttackPatterns = true; + } else if (type === 'threat' && attackPatterns?.stixCoreRelationships?.edges?.length > 0) { + hasAttackPatterns = true; + } + + 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 handleClose = () => { setSimulationType('technical'); setInterval(2); - setUseGenAI(false); helpers.handleClearAllFilters(); setOpen(false); }; @@ -158,10 +256,13 @@ const StixCoreObjectSimulationResult = ({ id, type }) => { commitMutationGenerateContainer({ variables: { id, - interval, - selection, - simulationType, - useAI: useGenAI, + simulationConfig: { + interval, + selection, + simulationType, + platforms, + architecture, + }, filters, }, onCompleted: (response) => { @@ -180,10 +281,13 @@ const StixCoreObjectSimulationResult = ({ id, type }) => { commitMutationGenerateThreat({ variables: { id, - interval, - selection, - simulationType, - useAI: useGenAI, + simulationConfig: { + interval, + selection, + simulationType, + platforms, + architecture, + }, filters, }, onCompleted: (response) => { @@ -202,10 +306,13 @@ const StixCoreObjectSimulationResult = ({ id, type }) => { commitMutationGenerateVictim({ variables: { id, - interval, - selection, - simulationType, - useAI: useGenAI, + simulationConfig: { + interval, + selection, + simulationType, + platforms, + architecture, + }, filters, }, onCompleted: (response) => { @@ -345,50 +452,110 @@ const StixCoreObjectSimulationResult = ({ id, type }) => { /> ); }; + + // Validation for Platforms + useEffect(() => { + if (platforms.length === 0) { + setPlatformError(t_i18n('This field should not be empty')); + } else { + setPlatformError(''); + } + }, [platforms]); + const renderForm = () => { return ( <> + + {t_i18n('Simulation type')} + + + {(simulationType !== 'simulated') && ( + <> + {!hasAttackPatterns && ( + + {t_i18n('Technical (payloads) require attack patterns in this entity.')} + + )} + + platforms.includes(platform.value))} + onChange={(_event, newValue) => { + const newSelectedValues = newValue.map((platform) => platform.value); + setPlatforms(newSelectedValues); + }} + getOptionLabel={(option) => option.label} + renderInput={(params) => ( + + )} + renderOption={(props, option) => ( +
  • +
    {option.label ?? ''}
    +
  • + )} + disabled={!hasAttackPatterns} + /> +
    + + {t_i18n('Targeted architecture')} + + + + )} setInterval(Number.isNaN(parseInt(event.target.value, 10)) ? 1 : parseInt(event.target.value, 10))} style={fieldSpacingContainerStyle} + disabled={!canGenerateScenario()} /> - {t_i18n('Number of injects by attack pattern')} + {t_i18n('Number of injects generated by attack pattern and platform')} - setUseGenAI(event.target.checked)} /> - } - /> - - {t_i18n('Simulation type')} - -
    diff --git a/opencti-platform/opencti-front/src/schema/relay.schema.graphql b/opencti-platform/opencti-front/src/schema/relay.schema.graphql index a38ae8c95f8e..2e1a30642636 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 + obasContainerGenerateScenario(id: ID!, simulationConfig: SimulationConfig, filters: FilterGroup): GenerationResponse + obasThreatGenerateScenario(id: ID!, simulationConfig: SimulationConfig, filters: FilterGroup): GenerationResponse + obasVictimGenerateScenario(id: ID!, simulationConfig: SimulationConfig, filters: FilterGroup): GenerationResponse deleteOperationRestore(id: ID!): ID deleteOperationConfirm(id: ID!): ID supportPackageAdd(input: SupportPackageAddInput!): SupportPackage @@ -12313,6 +12313,30 @@ 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 + attackPatternsWithoutInjectorContracts: String +} + 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..cc300f38bac6 100644 --- a/opencti-platform/opencti-graphql/src/database/xtm-obas.ts +++ b/opencti-platform/opencti-graphql/src/database/xtm-obas.ts @@ -46,11 +46,46 @@ 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 importFilter: any = { + mode: 'and', + filters: [ + { + key: 'injector_contract_attack_patterns', + 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: [ + ...importFilter.filters, + 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 }); } diff --git a/opencti-platform/opencti-graphql/src/generated/graphql.ts b/opencti-platform/opencti-graphql/src/generated/graphql.ts index ec872ea6b070..1c82aa166b71 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,12 @@ export enum Format { Text = 'text' } +export type GenerationResponse = { + __typename?: 'GenerationResponse'; + attackPatternsWithoutInjectorContracts?: Maybe; + urlResponse?: Maybe; +}; + export type GetMetrics = { __typename?: 'GetMetrics'; total?: Maybe; @@ -13739,9 +13750,9 @@ export type Mutation = { notifierAdd?: Maybe; notifierDelete?: Maybe; notifierFieldPatch?: Maybe; - obasContainerGenerateScenario?: Maybe; - obasThreatGenerateScenario?: Maybe; - obasVictimGenerateScenario?: Maybe; + obasContainerGenerateScenario?: Maybe; + obasThreatGenerateScenario?: Maybe; + obasVictimGenerateScenario?: Maybe; observedDataAdd?: Maybe; observedDataEdit?: Maybe; opinionAdd?: Maybe; @@ -15004,30 +15015,21 @@ export type MutationNotifierFieldPatchArgs = { export type MutationObasContainerGenerateScenarioArgs = { filters?: InputMaybe; id: Scalars['ID']['input']; - interval?: InputMaybe; - selection?: InputMaybe; - simulationType?: InputMaybe; - useAI?: InputMaybe; + simulationConfig?: InputMaybe; }; export type MutationObasThreatGenerateScenarioArgs = { filters?: InputMaybe; id: Scalars['ID']['input']; - interval?: InputMaybe; - selection?: InputMaybe; - simulationType?: InputMaybe; - useAI?: InputMaybe; + simulationConfig?: InputMaybe; }; export type MutationObasVictimGenerateScenarioArgs = { filters?: InputMaybe; id: Scalars['ID']['input']; - interval?: InputMaybe; - selection?: InputMaybe; - simulationType?: InputMaybe; - useAI?: InputMaybe; + simulationConfig?: InputMaybe; }; @@ -18674,6 +18676,12 @@ export type PhoneNumberAddInput = { value?: InputMaybe; }; +export enum Platform { + Linux = 'Linux', + MacOs = 'MacOS', + Windows = 'Windows' +} + export type PlatformCriticalAlert = { __typename?: 'PlatformCriticalAlert'; details?: Maybe; @@ -23764,6 +23772,14 @@ export type SettingsMessageInput = { recipients?: InputMaybe>; }; +export type SimulationConfig = { + architecture?: InputMaybe; + interval?: InputMaybe; + platforms?: InputMaybe>>; + selection?: InputMaybe; + simulationType: SimulationType; +}; + export enum SimulationType { Mixed = 'mixed', Simulated = 'simulated', @@ -31021,6 +31037,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 +31317,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 +31557,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 +31650,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 +32146,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 +32432,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 +35469,12 @@ export type FintelTemplateWidgetResolvers; }>; +export type GenerationResponseResolvers = ResolversObject<{ + attackPatternsWithoutInjectorContracts?: Resolver, ParentType, ContextType>; + urlResponse?: Resolver, ParentType, ContextType>; + __isTypeOf?: IsTypeOfResolverFn; +}>; + export type GetMetricsResolvers = ResolversObject<{ total?: Resolver, ParentType, ContextType>; __isTypeOf?: IsTypeOfResolverFn; @@ -37449,9 +37477,9 @@ export type MutationResolvers, ParentType, ContextType, RequireFields>; notifierDelete?: Resolver, ParentType, ContextType, RequireFields>; notifierFieldPatch?: Resolver, ParentType, ContextType, RequireFields>; - obasContainerGenerateScenario?: Resolver, ParentType, ContextType, RequireFields>; - obasThreatGenerateScenario?: Resolver, ParentType, ContextType, RequireFields>; - obasVictimGenerateScenario?: Resolver, ParentType, ContextType, RequireFields>; + obasContainerGenerateScenario?: Resolver, ParentType, ContextType, RequireFields>; + obasThreatGenerateScenario?: Resolver, ParentType, ContextType, RequireFields>; + obasVictimGenerateScenario?: Resolver, ParentType, ContextType, RequireFields>; observedDataAdd?: Resolver, ParentType, ContextType, RequireFields>; observedDataEdit?: Resolver, ParentType, ContextType, RequireFields>; opinionAdd?: Resolver, ParentType, ContextType, RequireFields>; @@ -42219,6 +42247,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/xtm.graphql b/opencti-platform/opencti-graphql/src/modules/xtm/xtm.graphql index 1fbe442bf534..3d1f277a4683 100644 --- a/opencti-platform/opencti-graphql/src/modules/xtm/xtm.graphql +++ b/opencti-platform/opencti-graphql/src/modules/xtm/xtm.graphql @@ -15,6 +15,29 @@ 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 + attackPatternsWithoutInjectorContracts: String +} + type SimulationsResult { unknown: Int success: Int @@ -33,7 +56,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]) + obasContainerGenerateScenario(id: ID!, simulationConfig: SimulationConfig, filters: FilterGroup): GenerationResponse @auth(for: [KNOWLEDGE_KNUPDATE]) + obasThreatGenerateScenario(id: ID!, simulationConfig: SimulationConfig, filters: FilterGroup): GenerationResponse @auth(for: [KNOWLEDGE_KNUPDATE]) + obasVictimGenerateScenario(id: ID!, simulationConfig: SimulationConfig, filters: FilterGroup): GenerationResponse @auth(for: [KNOWLEDGE_KNUPDATE]) } From 804cf64feede952ca8b4c2f68f79d9cb7a0e21ba Mon Sep 17 00:00:00 2001 From: Stephanya Casanova Date: Tue, 17 Dec 2024 12:11:22 +0100 Subject: [PATCH 2/8] [frontend/backend] Add placeholder for ttp not covered --- opencti-platform/opencti-front/lang/front/de.json | 3 ++- opencti-platform/opencti-front/lang/front/en.json | 3 ++- opencti-platform/opencti-front/lang/front/es.json | 3 ++- opencti-platform/opencti-front/lang/front/fr.json | 3 ++- opencti-platform/opencti-front/lang/front/ja.json | 3 ++- opencti-platform/opencti-front/lang/front/ko.json | 3 ++- opencti-platform/opencti-front/lang/front/zh.json | 3 ++- .../StixCoreObjectSimulationResult.jsx | 14 ++++++++++++-- .../opencti-graphql/src/database/xtm-obas.ts | 6 +++++- 9 files changed, 31 insertions(+), 10 deletions(-) diff --git a/opencti-platform/opencti-front/lang/front/de.json b/opencti-platform/opencti-front/lang/front/de.json index 4d263e215b70..216c32965a71 100644 --- a/opencti-platform/opencti-front/lang/front/de.json +++ b/opencti-platform/opencti-front/lang/front/de.json @@ -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", @@ -2856,7 +2857,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 the Openbas catalog : ": "Die folgenden TTPs sind nicht im Openbas-Katalog enthalten:", + "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.", diff --git a/opencti-platform/opencti-front/lang/front/en.json b/opencti-platform/opencti-front/lang/front/en.json index d6ecaf7b1d2f..ea779f449f31 100644 --- a/opencti-platform/opencti-front/lang/front/en.json +++ b/opencti-platform/opencti-front/lang/front/en.json @@ -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", @@ -2856,7 +2857,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 the Openbas catalog : ": "The following TTPs are not covered in the Openbas catalog : ", + "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.", diff --git a/opencti-platform/opencti-front/lang/front/es.json b/opencti-platform/opencti-front/lang/front/es.json index fb56aad1c415..8c42425b180b 100644 --- a/opencti-platform/opencti-front/lang/front/es.json +++ b/opencti-platform/opencti-front/lang/front/es.json @@ -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", @@ -2856,7 +2857,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 the Openbas catalog : ": "Los siguientes TTPs no están cubiertos en el catálogo Openbas :", + "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.", diff --git a/opencti-platform/opencti-front/lang/front/fr.json b/opencti-platform/opencti-front/lang/front/fr.json index 9109cc3c5401..0a6ba6ba4731 100644 --- a/opencti-platform/opencti-front/lang/front/fr.json +++ b/opencti-platform/opencti-front/lang/front/fr.json @@ -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", @@ -2856,7 +2857,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 the Openbas catalog : ": "Les TTP suivantes ne sont pas couvertes par le catalogue Openbas :", + "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.", diff --git a/opencti-platform/opencti-front/lang/front/ja.json b/opencti-platform/opencti-front/lang/front/ja.json index c805fb882b24..a3cd3d684187 100644 --- a/opencti-platform/opencti-front/lang/front/ja.json +++ b/opencti-platform/opencti-front/lang/front/ja.json @@ -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": "非活性", @@ -2856,7 +2857,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 the Openbas catalog : ": "以下の TTP は Openbas のカタログではカバーされていません:", + "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}リレーションシップ/参照がリストアされます。", diff --git a/opencti-platform/opencti-front/lang/front/ko.json b/opencti-platform/opencti-front/lang/front/ko.json index fefcd9c981b5..c75baaac0a2b 100644 --- a/opencti-platform/opencti-front/lang/front/ko.json +++ b/opencti-platform/opencti-front/lang/front/ko.json @@ -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": "비활성", @@ -2856,7 +2857,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 the Openbas catalog : ": "다음 TTP는 Openbas 카탈로그에서 다루지 않습니다:", + "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} 관계/참조가 복원됩니다.", diff --git a/opencti-platform/opencti-front/lang/front/zh.json b/opencti-platform/opencti-front/lang/front/zh.json index bdf6141883d2..ae2bf953b607 100644 --- a/opencti-platform/opencti-front/lang/front/zh.json +++ b/opencti-platform/opencti-front/lang/front/zh.json @@ -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": "不活跃", @@ -2856,7 +2857,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 the Openbas catalog : ": "Openbas 目录中不包括以下 TTP:", + "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} 关系/引用。", 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 8b409ad1a8cf..1acc24823c20 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 @@ -615,8 +615,18 @@ const StixCoreObjectSimulationResult = ({ id, type }) => { {result.attackPatternsWithoutInjectorContracts && result.attackPatternsWithoutInjectorContracts.trim() !== '' && ( - {t_i18n('The following TTPs are not covered in the Openbas catalog : ')} - {result.attackPatternsWithoutInjectorContracts} + {t_i18n('The following TTPs are not covered in your OpenBAS catalog : ')} +
      + {result.attackPatternsWithoutInjectorContracts.split(',').map((ttp, index) => ( +
    • {ttp}
    • + ))} +
    + {t_i18n('In response, we have created placeholders for these TTPs.')}
    )} diff --git a/opencti-platform/opencti-graphql/src/database/xtm-obas.ts b/opencti-platform/opencti-graphql/src/database/xtm-obas.ts index cc300f38bac6..17e57f28d12a 100644 --- a/opencti-platform/opencti-graphql/src/database/xtm-obas.ts +++ b/opencti-platform/opencti-graphql/src/database/xtm-obas.ts @@ -159,7 +159,9 @@ export const createInjectInScenario = async ( title: string, dependsDuration: number, content: string | null, - tags: Label[] + tags: Label[], + enabled: boolean, + description: string, ) => { const httpClient = buildXTmOpenBasHttpClient(); try { @@ -178,6 +180,8 @@ export const createInjectInScenario = async ( inject_depends_duration: dependsDuration, inject_content: content, inject_tags: obasTagsIds, + inject_enabled: enabled, + inject_description: description, } ); return inject; From 0d251e4c037d9abd2616fb769dfd1fd7bfb7266e Mon Sep 17 00:00:00 2001 From: Stephanya Casanova Date: Thu, 2 Jan 2025 08:59:51 +0100 Subject: [PATCH 3/8] [backend/frontend] refact simulation generation from with formik and rebase --- .../StixCoreObjectSimulationResult.jsx | 307 ++++++++++-------- .../src/modules/xtm/xtm-domain.js | 190 ++++++----- 2 files changed, 281 insertions(+), 216 deletions(-) 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 1acc24823c20..ea42a2b84567 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,13 +1,9 @@ -import React, { useEffect, useState } from 'react'; +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 Box from '@mui/material/Box'; import { graphql, useLazyLoadQuery } from 'react-relay'; import DialogActions from '@mui/material/DialogActions'; @@ -18,7 +14,8 @@ 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 { Autocomplete } from '@mui/material'; +import { Field, Form, Formik } from 'formik'; +import * as Yup from 'yup'; import EEChip from '../entreprise_edition/EEChip'; import Drawer from '../drawer/Drawer'; import Chart from '../charts/Chart'; @@ -36,6 +33,10 @@ import { emptyFilterGroup } from '../../../../utils/filters/filtersUtils'; import useApiMutation from '../../../../utils/hooks/useApiMutation'; import Transition from '../../../../components/Transition'; import useXTM from '../../../../utils/hooks/useXTM'; +import SelectField from '../../../../components/fields/SelectField'; +import AutocompleteField from '../../../../components/AutocompleteField'; +import TextField from '../../../../components/TextField'; +import { useDynamicSchemaCreationValidation, yupShapeConditionalRequired } from '../../../../utils/hooks/useEntitySettings'; const useStyles = makeStyles((theme) => ({ simulationResults: { @@ -184,9 +185,9 @@ const StixCoreObjectSimulationResult = ({ id, type }) => { const { enabled, configured } = useAI(); const isSimulatedEmailsAvailable = enabled && configured && isEnterpriseEdition; const [simulationType, setSimulationType] = useState('technical'); - const [platforms, setPlatforms] = useState(['Windows']); - const [architecture, setArchitecture] = useState('x86_64'); - const [selection, setSelection] = useState('random'); + const [platforms, setPlatforms] = useState([{ label: 'Windows', value: 'Windows' }]); + const architecture = 'x86_64'; + const selection = 'random'; const [interval, setInterval] = useState(2); const [isSubmitting, setIsSubmitting] = useState(false); const [result, setResult] = useState(null); @@ -194,13 +195,6 @@ const StixCoreObjectSimulationResult = ({ id, type }) => { const [filters, helpers] = useFiltersState(emptyFilterGroup); const { t_i18n } = useFormatter(); const isGrantedToUpdate = useGranted([KNOWLEDGE_KNUPDATE]); - const [platformError, setPlatformError] = useState(''); - - const platformOptions = [ - { label: 'Windows', value: 'Windows' }, - { label: 'Linux', value: 'Linux' }, - { label: 'MacOS', value: 'MacOS' }, - ]; // Determine the query based on the type let attackPatternsQuery; @@ -216,12 +210,10 @@ const StixCoreObjectSimulationResult = ({ id, type }) => { const attackPatterns = useLazyLoadQuery(attackPatternsQuery, { id }); // Check if there are attack patterns in the entity - let hasAttackPatterns = false; - if (type === 'container' && attackPatterns?.stixCoreObject?.objects?.edges?.length > 0) { - hasAttackPatterns = true; - } else if (type === 'threat' && attackPatterns?.stixCoreRelationships?.edges?.length > 0) { - hasAttackPatterns = true; - } + const hasAttackPatterns = ( + (type === 'container' && attackPatterns?.stixCoreObject?.objects?.edges?.length > 0) + || (type === 'threat' && attackPatterns?.stixCoreRelationships?.edges?.length > 0) + ); const canGenerateScenario = () => { return ( @@ -331,6 +323,7 @@ const StixCoreObjectSimulationResult = ({ id, type }) => { // do nothing } }; + const renderCharts = () => { return ( { ); }; - // Validation for Platforms - useEffect(() => { - if (platforms.length === 0) { - setPlatformError(t_i18n('This field should not be empty')); - } else { - setPlatformError(''); - } - }, [platforms]); + const initialValues = { + simulationType, + platforms, + architecture, + interval, + selection, + }; + + const mandatoryAttributes = ['simulationtype', 'interval', 'selection']; + const basicShape = yupShapeConditionalRequired({ + simulationType: Yup.string().required(t_i18n('This field is required')), + 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')), + 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')), + }, mandatoryAttributes); + + const simulationGenerationValidator = useDynamicSchemaCreationValidation( + mandatoryAttributes, + basicShape, + ); + + const platformOptions = [ + { label: 'Windows', value: 'Windows' }, + { label: 'Linux', value: 'Linux' }, + { label: 'MacOS', value: 'MacOS' }, + ]; const renderForm = () => { return ( - <> - - {t_i18n('Simulation type')} - - - {(simulationType !== 'simulated') && ( - <> - {!hasAttackPatterns && ( - { + handleGenerate(values); + }} + > + {({ values }) => ( +
    +
    + - {t_i18n('Technical (payloads) require attack patterns in this entity.')} - - )} - - platforms.includes(platform.value))} - onChange={(_event, newValue) => { - const newSelectedValues = newValue.map((platform) => platform.value); - setPlatforms(newSelectedValues); - }} - getOptionLabel={(option) => option.label} - renderInput={(params) => ( - - )} - renderOption={(props, option) => ( -
  • -
    {option.label ?? ''}
    -
  • + + {t_i18n('Technical (payloads)')} + + + {t_i18n('Simulated emails (generated by AI)')} + + + {t_i18n('Mixed (both)')} + +
    +
    + + {values.simulationType !== 'simulated' && ( + <> + {!hasAttackPatterns && ( + + {t_i18n('Technical (payloads) require attack patterns in this entity.')} + )} - disabled={!hasAttackPatterns} + +
    + setPlatforms(newValue)} + renderOption={(props, option) => ( +
  • +
    {option.label ?? ''}
    +
  • + )} + disabled={!hasAttackPatterns} + /> +
    + +
    + + x86_64 + arm64 + +
    + + )} + +
    + - - - {t_i18n('Targeted architecture')} - - - + {t_i18n('Cancel')} + + +
    +
    )} - setInterval(Number.isNaN(parseInt(event.target.value, 10)) ? 1 : parseInt(event.target.value, 10))} - style={fieldSpacingContainerStyle} - disabled={!canGenerateScenario()} - /> - - {t_i18n('Number of injects generated by attack pattern and platform')} - - -
    - - -
    - + ); }; + const renderCooking = () => { return (
    @@ -607,6 +631,7 @@ const StixCoreObjectSimulationResult = ({ id, type }) => {
    ); }; + const renderResult = () => { return ( <> @@ -637,15 +662,15 @@ const StixCoreObjectSimulationResult = ({ id, type }) => { ); }; + const renderResultError = () => { return ( - <> - } severity="error"> - {resultError} - - + } severity="error"> + {resultError} + ); }; + return ( <> {!oBasDisableDisplay && ( 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..b552ff165c01 100644 --- a/opencti-platform/opencti-graphql/src/modules/xtm/xtm-domain.js +++ b/opencti-platform/opencti-graphql/src/modules/xtm/xtm-domain.js @@ -12,15 +12,15 @@ 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, createInjectInScenario as obasCreateInjectInScenario, createScenario as obasCreateScenario, getAttackPatterns as obasGetAttackPatterns, - getInjectorContracts as obasGetInjectorContracts, - getKillChainPhases as obasGetKillChainPhases, + getKillChainPhases, getScenarioResult as obasGetScenarioResult, + searchInjectorContracts } from '../../database/xtm-obas'; import { isNotEmptyField } from '../../database/utils'; import { checkEnterpriseEdition } from '../../enterprise-edition/ee'; @@ -76,33 +76,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 createInjectInScenario( + scenarioId, + 'openbas_manual', + 'd02e9132-b9d0-4daa-b3b1-4b9871f8472c', + 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) => { @@ -289,9 +290,23 @@ const generateKillChainEmail = async (killChainPhaseName, killChainPhasesListOfN ); }; -export const generateOpenBasScenario = async (context, user, stixCoreObject, attackPatterns, labels, author, simulationType, interval, selection, useAI) => { +export const generateOpenBasScenario = async ( + context, + user, + stixCoreObject, + attackPatterns, + labels, + author, + simulationConfig +) => { + const { interval, selection, simulationType = 'technical', platforms = ['Windows'], architecture = 'x86_64' } = simulationConfig; + + 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); @@ -300,7 +315,7 @@ export const generateOpenBasScenario = async (context, user, stixCoreObject, att 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,19 +327,18 @@ 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 getKillChainPhases(); + 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.'); - } + if (simulationType !== 'technical' && attackPatterns.length === 0) { // eslint-disable-next-line no-restricted-syntax for (const obasKillChainPhase of sortedObasKillChainPhases) { const killChainPhaseName = obasKillChainPhase.phase_name; @@ -336,6 +350,7 @@ export const generateOpenBasScenario = async (context, user, stixCoreObject, att } else { logApp.debug('[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 @@ -348,13 +363,20 @@ export const generateOpenBasScenario = async (context, user, stixCoreObject, att 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) - ); + 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 sortByKillChainPhase = R.sortBy(R.path(['attack_pattern_kill_chain_phase', 'phase_order'])); - const sortedEnrichedFilteredObasAttackPatterns = sortByKillChainPhase(enrichedFilteredObasAttackPatterns); + const sortedEnrichedFilteredObasAttackPatterns = enrichedFilteredObasAttackPatterns.sort((a, b) => { + return a.attack_pattern_kill_chain_phase.phase_order - b.attack_pattern_kill_chain_phase.phase_order; + }); + + // Initialize an array to collect attack patterns without contracts + const attackPatternsWithoutInjectorContracts = []; // Get the injector contracts // eslint-disable-next-line no-restricted-syntax @@ -370,11 +392,37 @@ export const generateOpenBasScenario = async (context, user, stixCoreObject, att ); dependsOnDuration += (interval * 60); } else { - createAndInjectScenarioPromises.push(generateTechnicalAttackPattern(obasAttackPattern, selection, simulationType, obasScenario, dependsOnDuration, interval)); - dependsOnDuration += (interval * 60); + const obasInjectorContracts = await searchInjectorContracts(obasAttackPattern.attack_pattern_external_id, platforms, architecture); + + if (obasInjectorContracts.length === 0) { + attackPatternsWithoutInjectorContracts.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.externalId, 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 + logApp.info(`[OPENCTI-MODULE][XTM] simulationType ${simulationType} not implemented yet.`); + } + } } } // end loop for - await Promise.all(createAndInjectScenarioPromises); + + try { + await Promise.all(createAndInjectScenarioPromises); + } catch (error) { + logApp.error('[OPENCTI-MODULE][XTM] Error in scenario generation', { error }); + } const endingTime = new Date().getTime(); const totalTime = endingTime - startingTime; @@ -386,48 +434,40 @@ export const generateOpenBasScenario = async (context, user, stixCoreObject, att 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`; + logApp.info(`[OPENCTI-MODULE][XTM] Generating ${createAndInjectScenarioPromises.length} emails took ${totalTime} ms`, { simulationType }); + + return { + urlResponse: `${XTM_OPENBAS_URL}/admin/scenarios/${obasScenario.scenario_id}/injects`, + attackPatternsWithoutInjectorContracts: attackPatternsWithoutInjectorContracts.join(',') + }; }; 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); - } + 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 generateOpenBasScenario(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); - } + 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 generateOpenBasScenario(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); - } + 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 +486,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 generateOpenBasScenario(context, user, stixCoreObject, attackPatterns, labels, (author && author.length > 0 ? author.at(0) : 'Unknown'), simulationConfig); }; From 98f33df68622f5e00a4c7823727c7cd1e7c8faac Mon Sep 17 00:00:00 2001 From: Stephanya Casanova Date: Sat, 11 Jan 2025 16:59:47 +0100 Subject: [PATCH 4/8] [frontend/backend] Refact formControl to formik --- .../opencti-front/lang/front/de.json | 6 +- .../opencti-front/lang/front/en.json | 6 +- .../opencti-front/lang/front/es.json | 6 +- .../opencti-front/lang/front/fr.json | 6 +- .../opencti-front/lang/front/ja.json | 6 +- .../opencti-front/lang/front/ko.json | 6 +- .../opencti-front/lang/front/zh.json | 6 +- .../StixCoreObjectSimulationResult.jsx | 375 +++++++++--------- .../src/modules/xtm/xtm-domain.js | 5 +- 9 files changed, 218 insertions(+), 204 deletions(-) diff --git a/opencti-platform/opencti-front/lang/front/de.json b/opencti-platform/opencti-front/lang/front/de.json index 216c32965a71..8282b4dc095e 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", @@ -1581,6 +1581,8 @@ "INTERNAL_INGESTION": "Dateneingabe", "Interval": "Intervall", "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", @@ -1870,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", @@ -2922,7 +2925,6 @@ "This field must be >= 1": "Dieses Feld muss >= 1 sein", "This field must be a number": "Dieses Feld muss eine Zahl sein", "This field must only contain alphanumeric chars, dashes and space": "Dieses Feld darf nur alphanumerische Zeichen, Bindestriche und Leerzeichen enthalten", - "This field should not be empty": "Dieses Feld sollte nicht leer sein", "This file is not in the specified format": "Diese Datei hat nicht das angegebene Format", "This file is too large": "Diese Datei ist zu groß", "This filter contains imbricated filter groups, that are not fully supported yet in the platform display and can only be edited via the API. They might have been created via the API or a migration from a previous filter format. For your information, here is the content of the filter object: ": "Dieser Filter enthält ineinander verschachtelte Filtergruppen, die in der Plattformanzeige noch nicht vollständig unterstützt werden und nur über die API bearbeitet werden können. Sie können über die API oder eine Migration von einem früheren Filterformat erstellt worden sein. Zu Ihrer Information, hier ist der Inhalt des Filterobjekts:", diff --git a/opencti-platform/opencti-front/lang/front/en.json b/opencti-platform/opencti-front/lang/front/en.json index ea779f449f31..0549655bdb66 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", @@ -1581,6 +1581,8 @@ "INTERNAL_INGESTION": "Data ingestion", "Interval": "Interval", "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", @@ -1870,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", @@ -2922,7 +2925,6 @@ "This field must be >= 1": "This field must be >= 1", "This field must be a number": "This field must be a number", "This field must only contain alphanumeric chars, dashes and space": "This field must only contain alphanumeric chars, dashes and space", - "This field should not be empty": "This field should not be empty", "This file is not in the specified format": "This file is not in the specified format", "This file is too large": "This file is too large", "This filter contains imbricated filter groups, that are not fully supported yet in the platform display and can only be edited via the API. They might have been created via the API or a migration from a previous filter format. For your information, here is the content of the filter object: ": "This filter contains imbricated filter groups, that are not fully supported yet in the platform display and can only be edited via the API. They might have been created via the API or a migration from a previous filter format. For your information, here is the content of the filter object: ", diff --git a/opencti-platform/opencti-front/lang/front/es.json b/opencti-platform/opencti-front/lang/front/es.json index 8c42425b180b..0585c1c3c229 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", @@ -1581,6 +1581,8 @@ "INTERNAL_INGESTION": "Ingesta de datos", "Interval": "Intervalo", "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", @@ -1870,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", @@ -2922,7 +2925,6 @@ "This field must be >= 1": "Este campo debe ser >= 1", "This field must be a number": "Este campo debe ser un número", "This field must only contain alphanumeric chars, dashes and space": "Este campo debe contener solamente caracteres alfanuméricos, guiones y espacios", - "This field should not be empty": "Este campo no debe estar vacío", "This file is not in the specified format": "Este archivo no tiene el formato especificado", "This file is too large": "Este archivo es demasiado grande", "This filter contains imbricated filter groups, that are not fully supported yet in the platform display and can only be edited via the API. They might have been created via the API or a migration from a previous filter format. For your information, here is the content of the filter object: ": "Este filtro contiene grupos de filtros imbricados, que aún no son completamente compatibles en la visualización de la plataforma y solo se pueden editar a través de la API. Es posible que se hayan creado a través de la API o una migración desde un formato de filtro anterior. Para tu información, aquí está el contenido del objeto de filtro:", diff --git a/opencti-platform/opencti-front/lang/front/fr.json b/opencti-platform/opencti-front/lang/front/fr.json index 0a6ba6ba4731..e71425f96b07 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", @@ -1581,6 +1581,8 @@ "INTERNAL_INGESTION": "L'ingestion de données", "Interval": "Intervalle", "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", @@ -1870,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", @@ -2922,7 +2925,6 @@ "This field must be >= 1": "Ce champ doit être >= 1", "This field must be a number": "Ce champ doit être un nombre", "This field must only contain alphanumeric chars, dashes and space": "Ce champ ne peut contenir que des caractères alphanumériques, des tirets et des espaces", - "This field should not be empty": "Ce champ ne doit pas être vide", "This file is not in the specified format": "Ce fichier n'est pas au format spécifié", "This file is too large": "Ce fichier est trop volumineux", "This filter contains imbricated filter groups, that are not fully supported yet in the platform display and can only be edited via the API. They might have been created via the API or a migration from a previous filter format. For your information, here is the content of the filter object: ": "Ce filtre contient des groupes de filtres imbriqués, qui ne sont pas encore totalement pris en charge dans l'affichage de la plateforme et ne peuvent être modifiés que via l'API. Ils peuvent avoir été créés via l'API ou lors d'une migration à partir d'un format de filtre précédent. Pour votre information, voici le contenu de l'objet de filtre:", diff --git a/opencti-platform/opencti-front/lang/front/ja.json b/opencti-platform/opencti-front/lang/front/ja.json index a3cd3d684187..88eb7ed112a0 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": "アカウントの有効期限", @@ -1581,6 +1581,8 @@ "INTERNAL_INGESTION": "データの取り込み", "Interval": "インターバル", "Interval between injections (in minutes)": "注射の間隔(分)", + "Interval must be a positive number": "間隔は正の数でなければならない", + "Interval must be an integer": "間隔は整数でなければならない", "Intrusion set": "侵入セット", "Intrusion Sets": "侵入セット", "Intrusion sets": "侵入セット", @@ -1870,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", @@ -2922,7 +2925,6 @@ "This field must be >= 1": "このフィールドは>= 1でなければならない", "This field must be a number": "このフィールドは数字でなければなりません", "This field must only contain alphanumeric chars, dashes and space": "このフィールドに入力可能な文字はアルファベット、数字、\"-\", 半角スペースのみです", - "This field should not be empty": "このフィールドは空であってはならない", "This file is not in the specified format": "このファイルは指定された形式ではありません", "This file is too large": "このファイルは大きすぎます", "This filter contains imbricated filter groups, that are not fully supported yet in the platform display and can only be edited via the API. They might have been created via the API or a migration from a previous filter format. For your information, here is the content of the filter object: ": "このフィルターには、プラットフォームの表示ではまだ完全にサポートされていない、入れ子になったフィルターグループが含まれており、API経由でのみ編集することができます。これらはAPI経由で作成されたか、以前のフィルターフォーマットからの移行で作成された可能性があります。フィルターオブジェクトの内容は次のとおりです", diff --git a/opencti-platform/opencti-front/lang/front/ko.json b/opencti-platform/opencti-front/lang/front/ko.json index c75baaac0a2b..407e6fcc845b 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": "계정 만료일", @@ -1581,6 +1581,8 @@ "INTERNAL_INGESTION": "데이터 수집", "Interval": "간격", "Interval between injections (in minutes)": "주입 간격(분)", + "Interval must be a positive number": "간격은 양수여야 합니다", + "Interval must be an integer": "간격은 정수여야 합니다", "Intrusion set": "침입 세트", "Intrusion Sets": "침입 세트", "Intrusion sets": "침입 세트", @@ -1870,6 +1872,7 @@ "Minimum one event type": "최소한의 하나의 이벤트 유형", "Minimum one notifier": "최소한의 하나의 알림자", "Minimum one organization": "최소 하나의 조직", + "Minimum one platform": "최소 하나의 플랫폼", "Minimum one recipient": "최소 한 명의 수신자", "Minimum one trigger": "최소한의 하나의 트리거", "MinIO": "MinIO", @@ -2922,7 +2925,6 @@ "This field must be >= 1": "이 필드는 &\\\\;= 1이어야 합니다", "This field must be a number": "이 필드는 숫자여야 합니다", "This field must only contain alphanumeric chars, dashes and space": "이 필드는 영숫자, 대시 및 공백만 포함해야 합니다", - "This field should not be empty": "이 필드는 비어 있으면 안 됩니다", "This file is not in the specified format": "이 파일은 지정된 형식이 아닙니다", "This file is too large": "이 파일은 너무 큽니다", "This filter contains imbricated filter groups, that are not fully supported yet in the platform display and can only be edited via the API. They might have been created via the API or a migration from a previous filter format. For your information, here is the content of the filter object: ": "이 필터에는 플랫폼 디스플레이에서 아직 완전히 지원되지 않으며 API를 통해서만 편집할 수 있는 중첩된 필터 그룹이 포함되어 있습니다. 이는 API를 통해 생성되었거나 이전 필터 형식에서 마이그레이션된 것일 수 있습니다. 참고로 여기에 필터 객체의 내용이 있습니다: ", diff --git a/opencti-platform/opencti-front/lang/front/zh.json b/opencti-platform/opencti-front/lang/front/zh.json index ae2bf953b607..01fc38ec2774 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": "账户到期日期", @@ -1581,6 +1581,8 @@ "INTERNAL_INGESTION": "数据摄取", "Interval": "时间间隔", "Interval between injections (in minutes)": "注射间隔时间(分钟)", + "Interval must be a positive number": "间隔必须是正数", + "Interval must be an integer": "间隔必须是整数", "Intrusion set": "入侵集合", "Intrusion Sets": "入侵集合", "Intrusion sets": "入侵集合", @@ -1870,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", @@ -2922,7 +2925,6 @@ "This field must be >= 1": "此字段必须为 >= 1", "This field must be a number": "该字段必须为数字", "This field must only contain alphanumeric chars, dashes and space": "此字段只能包含字母、数字、字符、下划线和空格", - "This field should not be empty": "该字段不应为空", "This file is not in the specified format": "该文件不是指定格式", "This file is too large": "该文件太大", "This filter contains imbricated filter groups, that are not fully supported yet in the platform display and can only be edited via the API. They might have been created via the API or a migration from a previous filter format. For your information, here is the content of the filter object: ": "这个过滤器含有嵌套的过滤器组,目前平台的显示还不完全支持,只能通过 API 进行编辑。它们可能是通过 API 创建的,或者是从之前的过滤器格式迁移过来的。为了供您参考,这里是过滤器对象的内容:", 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 ea42a2b84567..cb39e5b1062b 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,6 +1,6 @@ import React, { useState } from 'react'; import { makeStyles, useTheme } from '@mui/styles'; -import { CheckOutlined, OpenInNewOutlined, SensorOccupiedOutlined, ShieldOutlined, TrackChangesOutlined, ErrorOutlined, LaunchOutlined } from '@mui/icons-material'; +import { CheckOutlined, ErrorOutlined, LaunchOutlined, OpenInNewOutlined, SensorOccupiedOutlined, ShieldOutlined, TrackChangesOutlined } from '@mui/icons-material'; import Tooltip from '@mui/material/Tooltip'; import Button from '@mui/material/Button'; import MenuItem from '@mui/material/MenuItem'; @@ -36,7 +36,6 @@ import useXTM from '../../../../utils/hooks/useXTM'; import SelectField from '../../../../components/fields/SelectField'; import AutocompleteField from '../../../../components/AutocompleteField'; import TextField from '../../../../components/TextField'; -import { useDynamicSchemaCreationValidation, yupShapeConditionalRequired } from '../../../../utils/hooks/useEntitySettings'; const useStyles = makeStyles((theme) => ({ simulationResults: { @@ -98,7 +97,7 @@ const stixCoreObjectSimulationResultObasStixCoreObjectSimulationsResultQuery = g const stixCoreObjectSimulationResultObasContainerGenerateScenarioMutation = graphql` mutation StixCoreObjectSimulationResultObasContainerGenerateScenarioMutation($id: ID!, $simulationConfig: SimulationConfig, $filters: FilterGroup) { - obasContainerGenerateScenario(id: $id, simulationConfig: $simulationConfig, filters: $filters){ + obasContainerGenerateScenario(id: $id, simulationConfig: $simulationConfig, filters: $filters){ urlResponse attackPatternsWithoutInjectorContracts } @@ -107,7 +106,7 @@ const stixCoreObjectSimulationResultObasContainerGenerateScenarioMutation = grap const stixCoreObjectSimulationResultObasThreatGenerateScenarioMutation = graphql` mutation StixCoreObjectSimulationResultObasThreatGenerateScenarioMutation($id: ID!, $simulationConfig: SimulationConfig, $filters: FilterGroup) { - obasThreatGenerateScenario(id: $id, simulationConfig: $simulationConfig, filters: $filters) { + obasThreatGenerateScenario(id: $id, simulationConfig: $simulationConfig, filters: $filters) { urlResponse attackPatternsWithoutInjectorContracts } @@ -116,7 +115,7 @@ const stixCoreObjectSimulationResultObasThreatGenerateScenarioMutation = graphql const stixCoreObjectSimulationResultObasVictimGenerateScenarioMutation = graphql` mutation StixCoreObjectSimulationResultObasVictimGenerateScenarioMutation($id: ID!, $simulationConfig: SimulationConfig, $filters: FilterGroup) { - obasVictimGenerateScenario(id: $id, simulationConfig: $simulationConfig, filters: $filters){ + obasVictimGenerateScenario(id: $id, simulationConfig: $simulationConfig, filters: $filters){ urlResponse attackPatternsWithoutInjectorContracts } @@ -126,7 +125,7 @@ const stixCoreObjectSimulationResultObasVictimGenerateScenarioMutation = graphql const StixCoreObjectSimulationResultAttackPatternsForContainersQuery = graphql` query StixCoreObjectSimulationResultAttackPatternsForContainersQuery($id: String!) { stixCoreObject(id: $id) { - id + id entity_type ... on Container { objects (types: ["Attack-Pattern"]){ @@ -150,9 +149,9 @@ const stixCoreObjectSimulationResultAttackPatternsForThreatsQuery = graphql` mode: and, filters: [ { - key: "relationship_type", - values: ["uses"], - }, + key: "relationship_type", + values: ["uses"], + }, { key: "fromOrToId", values: [$id], @@ -163,7 +162,7 @@ const stixCoreObjectSimulationResultAttackPatternsForThreatsQuery = graphql` } ], filterGroups: [ - + ], }) { edges { @@ -185,9 +184,9 @@ const StixCoreObjectSimulationResult = ({ id, type }) => { const { enabled, configured } = useAI(); const isSimulatedEmailsAvailable = enabled && configured && isEnterpriseEdition; const [simulationType, setSimulationType] = useState('technical'); - const [platforms, setPlatforms] = useState([{ label: 'Windows', value: 'Windows' }]); - const architecture = 'x86_64'; - const selection = 'random'; + const [platforms, setPlatforms] = useState(['Windows']); + const [architecture, setArchitecture] = useState('x86_64'); + const [selection, setSelection] = useState('random'); const [interval, setInterval] = useState(2); const [isSubmitting, setIsSubmitting] = useState(false); const [result, setResult] = useState(null); @@ -218,8 +217,8 @@ const StixCoreObjectSimulationResult = ({ id, type }) => { 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))) + || (simulationType === 'simulated' && enabled && configured && isEnterpriseEdition) + || (simulationType === 'mixed' && ((enabled && configured && isEnterpriseEdition) && (hasAttackPatterns && platforms.length > 0 && architecture))) ); }; @@ -324,6 +323,165 @@ const StixCoreObjectSimulationResult = ({ id, type }) => { } }; + 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 platformOptions = [ + { label: 'Windows', value: 'Windows' }, + { label: 'Linux', value: 'Linux' }, + { label: 'MacOS', value: 'MacOS' }, + ]; + + const initialValues = { + simulationType, + platforms, + architecture, + interval, + selection, + }; + + const opacity = (!hasAttackPatterns && simulationType) === 'technical' ? 0.38 : 1; + + 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.map((option) => option.value))} + 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('Multiple (limited to 5)')} + {t_i18n('One (random)')} + +
    +
    + + +
    +
    + )} +
    + ); + }; + const renderCharts = () => { return ( { ); }; - const initialValues = { - simulationType, - platforms, - architecture, - interval, - selection, - }; - - const mandatoryAttributes = ['simulationtype', 'interval', 'selection']; - const basicShape = yupShapeConditionalRequired({ - simulationType: Yup.string().required(t_i18n('This field is required')), - 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')), - 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')), - }, mandatoryAttributes); - - const simulationGenerationValidator = useDynamicSchemaCreationValidation( - mandatoryAttributes, - basicShape, - ); - - const platformOptions = [ - { label: 'Windows', value: 'Windows' }, - { label: 'Linux', value: 'Linux' }, - { label: 'MacOS', value: 'MacOS' }, - ]; - - const renderForm = () => { - return ( - { - handleGenerate(values); - }} - > - {({ values }) => ( -
    -
    - - - {t_i18n('Technical (payloads)')} - - - {t_i18n('Simulated emails (generated by AI)')} - - - {t_i18n('Mixed (both)')} - - -
    - - {values.simulationType !== 'simulated' && ( - <> - {!hasAttackPatterns && ( - - {t_i18n('Technical (payloads) require attack patterns in this entity.')} - - )} - -
    - setPlatforms(newValue)} - renderOption={(props, option) => ( -
  • -
    {option.label ?? ''}
    -
  • - )} - disabled={!hasAttackPatterns} - /> -
    - -
    - - x86_64 - arm64 - -
    - - )} - -
    - -
    - -
    - - {t_i18n('Multiple (limited to 5)')} - {t_i18n('One (random)')} - -
    - -
    - - -
    -
    - )} -
    - ); - }; - const renderCooking = () => { return (
    @@ -639,24 +641,24 @@ const StixCoreObjectSimulationResult = ({ id, type }) => { {t_i18n('The scenario has been correctly generated in your OpenBAS platform.')} {result.attackPatternsWithoutInjectorContracts && result.attackPatternsWithoutInjectorContracts.trim() !== '' && ( - - {t_i18n('The following TTPs are not covered in your OpenBAS catalog : ')} -
      - {result.attackPatternsWithoutInjectorContracts.split(',').map((ttp, index) => ( -
    • {ttp}
    • - ))} -
    - {t_i18n('In response, we have created placeholders for these TTPs.')} -
    + + {t_i18n('The following TTPs are not covered in your OpenBAS catalog : ')} +
      + {result.attackPatternsWithoutInjectorContracts.split(',').map((ttp, index) => ( +
    • {ttp}
    • + ))} +
    + {t_i18n('In response, we have created placeholders for these TTPs.')} +
    )} @@ -743,5 +745,4 @@ const StixCoreObjectSimulationResult = ({ id, type }) => { ); }; - export default StixCoreObjectSimulationResult; 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 b552ff165c01..1e5e80ca8d65 100644 --- a/opencti-platform/opencti-graphql/src/modules/xtm/xtm-domain.js +++ b/opencti-platform/opencti-graphql/src/modules/xtm/xtm-domain.js @@ -397,7 +397,7 @@ export const generateOpenBasScenario = async ( if (obasInjectorContracts.length === 0) { attackPatternsWithoutInjectorContracts.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.externalId, platforms, architecture, obasScenario.scenario_id, dependsOnDuration)); + 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); @@ -411,7 +411,7 @@ export const generateOpenBasScenario = async ( dependsOnDuration += (interval * 60); } } else { - // TODO + // TODO CASE Mixed (both) logApp.info(`[OPENCTI-MODULE][XTM] simulationType ${simulationType} not implemented yet.`); } } @@ -430,7 +430,6 @@ export const generateOpenBasScenario = async ( logApp.warn('[OPENCTI-MODULE][XTM] Long scenario generation time', { size: createAndInjectScenarioPromises.length, took: totalTime, - useAI, simulationType }); } From 0e99c659cfe3caa8036456655db2c27eb025eea9 Mon Sep 17 00:00:00 2001 From: Stephanya Casanova Date: Sun, 12 Jan 2025 00:28:41 +0100 Subject: [PATCH 5/8] [backend/frontend] Clean --- .../opencti-front/lang/front/de.json | 2 +- .../opencti-front/lang/front/en.json | 2 +- .../opencti-front/lang/front/es.json | 2 +- .../opencti-front/lang/front/fr.json | 2 +- .../opencti-front/lang/front/ja.json | 2 +- .../opencti-front/lang/front/ko.json | 2 +- .../opencti-front/lang/front/zh.json | 2 +- .../StixCoreObjectSimulationResult.jsx | 158 +++++++------ .../src/schema/relay.schema.graphql | 13 +- .../opencti-graphql/src/database/xtm-obas.ts | 18 +- .../opencti-graphql/src/generated/graphql.ts | 61 ++++- .../modules/xtm/deprecated/xtm-deprecated.ts | 8 + .../src/modules/xtm/deprecated/xtm-domain.js | 87 +++++++ .../modules/xtm/deprecated/xtm-resolver.ts | 12 + .../src/modules/xtm/deprecated/xtm.graphql | 5 + .../src/modules/xtm/xtm-domain.js | 219 ++++++++++-------- .../src/modules/xtm/xtm-resolver.ts | 14 +- .../src/modules/xtm/xtm.graphql | 14 +- 18 files changed, 407 insertions(+), 216 deletions(-) create mode 100644 opencti-platform/opencti-graphql/src/modules/xtm/deprecated/xtm-deprecated.ts create mode 100644 opencti-platform/opencti-graphql/src/modules/xtm/deprecated/xtm-domain.js create mode 100644 opencti-platform/opencti-graphql/src/modules/xtm/deprecated/xtm-resolver.ts create mode 100644 opencti-platform/opencti-graphql/src/modules/xtm/deprecated/xtm.graphql diff --git a/opencti-platform/opencti-front/lang/front/de.json b/opencti-platform/opencti-front/lang/front/de.json index 8282b4dc095e..5e2ffe5669dc 100644 --- a/opencti-platform/opencti-front/lang/front/de.json +++ b/opencti-platform/opencti-front/lang/front/de.json @@ -2828,7 +2828,7 @@ "team": "Organisiertes Team", "Technical": "Technisch", "Technical (payloads)": "Technisch (Nutzlasten)", - "Technical (payloads) require attack patterns in this entity.": "Technische (Nutzlasten) erfordern Angriffsmuster in dieser Einheit.", + "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", diff --git a/opencti-platform/opencti-front/lang/front/en.json b/opencti-platform/opencti-front/lang/front/en.json index 0549655bdb66..04b194ed1d92 100644 --- a/opencti-platform/opencti-front/lang/front/en.json +++ b/opencti-platform/opencti-front/lang/front/en.json @@ -2828,7 +2828,7 @@ "team": "Organized team", "Technical": "Technical", "Technical (payloads)": "Technical (payloads)", - "Technical (payloads) require attack patterns in this entity.": "Technical (payloads) require attack patterns in this entity.", + "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", diff --git a/opencti-platform/opencti-front/lang/front/es.json b/opencti-platform/opencti-front/lang/front/es.json index 0585c1c3c229..898722ff9376 100644 --- a/opencti-platform/opencti-front/lang/front/es.json +++ b/opencti-platform/opencti-front/lang/front/es.json @@ -2828,7 +2828,7 @@ "team": "Equipo organizado", "Technical": "Técnico", "Technical (payloads)": "Técnica (cargas útiles)", - "Technical (payloads) require attack patterns in this entity.": "Técnica (cargas útiles) requieren patrones de ataque en esta entidad.", + "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", diff --git a/opencti-platform/opencti-front/lang/front/fr.json b/opencti-platform/opencti-front/lang/front/fr.json index e71425f96b07..fa05d3dc7607 100644 --- a/opencti-platform/opencti-front/lang/front/fr.json +++ b/opencti-platform/opencti-front/lang/front/fr.json @@ -2828,7 +2828,7 @@ "team": "Equipe organisée", "Technical": "Technique", "Technical (payloads)": "Technique (charges utiles)", - "Technical (payloads) require attack patterns in this entity.": "Les données techniques (charges utiles) requièrent des schémas d'attaque dans cette entité.", + "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", diff --git a/opencti-platform/opencti-front/lang/front/ja.json b/opencti-platform/opencti-front/lang/front/ja.json index 88eb7ed112a0..eba12bcc598d 100644 --- a/opencti-platform/opencti-front/lang/front/ja.json +++ b/opencti-platform/opencti-front/lang/front/ja.json @@ -2828,7 +2828,7 @@ "team": "組織的なチーム", "Technical": "テクニカル", "Technical (payloads)": "テクニカル(ペイロード)", - "Technical (payloads) require attack patterns in this entity.": "技術的(ペイロード)には、このエンティティの攻撃パターンが必要である。", + "Technical (payloads) requires attack patterns in this entity.": "技術的(ペイロード)には、このエンティティの攻撃パターンが必要である。", "Technical date": "技術的な日時", "Technical elements (indicators & observables)": "技術的要素(インジケータと観測結果)", "Techniques": "技術", diff --git a/opencti-platform/opencti-front/lang/front/ko.json b/opencti-platform/opencti-front/lang/front/ko.json index 407e6fcc845b..1ccbe46dd765 100644 --- a/opencti-platform/opencti-front/lang/front/ko.json +++ b/opencti-platform/opencti-front/lang/front/ko.json @@ -2828,7 +2828,7 @@ "team": "조직된 팀", "Technical": "기술적", "Technical (payloads)": "기술적 (페이로드)", - "Technical (payloads) require attack patterns in this entity.": "기술(페이로드)은 이 엔티티에 공격 패턴이 필요합니다.", + "Technical (payloads) requires attack patterns in this entity.": "기술(페이로드)은 이 엔티티의 공격 패턴을 필요로 합니다.", "Technical date": "기술적 날짜", "Technical elements (indicators & observables)": "기술적 요소 (인디케이터 및 관찰 가능)", "Techniques": "기법", diff --git a/opencti-platform/opencti-front/lang/front/zh.json b/opencti-platform/opencti-front/lang/front/zh.json index 01fc38ec2774..3823f5678a71 100644 --- a/opencti-platform/opencti-front/lang/front/zh.json +++ b/opencti-platform/opencti-front/lang/front/zh.json @@ -2828,7 +2828,7 @@ "team": "团队", "Technical": "技术", "Technical (payloads)": "技术(有效载荷)", - "Technical (payloads) require attack patterns in this entity.": "技术(有效载荷)需要该实体中的攻击模式。", + "Technical (payloads) requires attack patterns in this entity.": "技术(有效载荷)需要该实体中的攻击模式。", "Technical date": "技术日期", "Technical elements (indicators & observables)": "技术元素(攻击指标和可观测数据)", "Techniques": "技术", 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 cb39e5b1062b..2b3feae206b1 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 @@ -95,29 +95,32 @@ const stixCoreObjectSimulationResultObasStixCoreObjectSimulationsResultQuery = g } `; -const stixCoreObjectSimulationResultObasContainerGenerateScenarioMutation = graphql` - mutation StixCoreObjectSimulationResultObasContainerGenerateScenarioMutation($id: ID!, $simulationConfig: SimulationConfig, $filters: FilterGroup) { - obasContainerGenerateScenario(id: $id, simulationConfig: $simulationConfig, filters: $filters){ +const stixCoreObjectSimulationResultObasContainerGenerateScenarioWithInjectPlaceholdersMutation = graphql` + mutation StixCoreObjectSimulationResultObasContainerGenerateScenarioWithInjectPlaceholdersMutation($id: ID!, $simulationConfig: SimulationConfig, $filters: FilterGroup) { + obasContainerGenerateScenarioWithInjectPlaceholders(id: $id, simulationConfig: $simulationConfig, filters: $filters){ urlResponse - attackPatternsWithoutInjectorContracts + attackPatternsNotAvailableInOpenBAS + hasInjectPlaceholders } } `; -const stixCoreObjectSimulationResultObasThreatGenerateScenarioMutation = graphql` - mutation StixCoreObjectSimulationResultObasThreatGenerateScenarioMutation($id: ID!, $simulationConfig: SimulationConfig, $filters: FilterGroup) { - obasThreatGenerateScenario(id: $id, simulationConfig: $simulationConfig, filters: $filters) { +const stixCoreObjectSimulationResultObasThreatGenerateScenarioWithInjectPlaceholdersMutation = graphql` + mutation StixCoreObjectSimulationResultObasThreatGenerateScenarioWithInjectPlaceholdersMutation($id: ID!, $simulationConfig: SimulationConfig, $filters: FilterGroup) { + obasThreatGenerateScenarioWithInjectPlaceholders(id: $id, simulationConfig: $simulationConfig, filters: $filters) { urlResponse - attackPatternsWithoutInjectorContracts + attackPatternsNotAvailableInOpenBAS + hasInjectPlaceholders } } `; -const stixCoreObjectSimulationResultObasVictimGenerateScenarioMutation = graphql` - mutation StixCoreObjectSimulationResultObasVictimGenerateScenarioMutation($id: ID!, $simulationConfig: SimulationConfig, $filters: FilterGroup) { - obasVictimGenerateScenario(id: $id, simulationConfig: $simulationConfig, filters: $filters){ +const stixCoreObjectSimulationResultObasVictimGenerateScenarioWithInjectPlaceholdersMutation = graphql` + mutation StixCoreObjectSimulationResultObasVictimGenerateScenarioWithInjectPlaceholdersMutation($id: ID!, $simulationConfig: SimulationConfig, $filters: FilterGroup) { + obasVictimGenerateScenarioWithInjectPlaceholders(id: $id, simulationConfig: $simulationConfig, filters: $filters){ urlResponse - attackPatternsWithoutInjectorContracts + attackPatternsNotAvailableInOpenBAS + hasInjectPlaceholders } } `; @@ -184,7 +187,7 @@ const StixCoreObjectSimulationResult = ({ id, type }) => { const { enabled, configured } = useAI(); const isSimulatedEmailsAvailable = enabled && configured && isEnterpriseEdition; const [simulationType, setSimulationType] = useState('technical'); - const [platforms, setPlatforms] = useState(['Windows']); + const [platforms, setPlatforms] = useState([{ label: 'Windows', value: 'Windows' }]); const [architecture, setArchitecture] = useState('x86_64'); const [selection, setSelection] = useState('random'); const [interval, setInterval] = useState(2); @@ -235,13 +238,14 @@ const StixCoreObjectSimulationResult = ({ id, type }) => { handleClose(); }; - const [commitMutationGenerateContainer] = useApiMutation(stixCoreObjectSimulationResultObasContainerGenerateScenarioMutation); - const [commitMutationGenerateThreat] = useApiMutation(stixCoreObjectSimulationResultObasThreatGenerateScenarioMutation); - const [commitMutationGenerateVictim] = useApiMutation(stixCoreObjectSimulationResultObasVictimGenerateScenarioMutation); + 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({ @@ -251,13 +255,13 @@ const StixCoreObjectSimulationResult = ({ id, type }) => { interval, selection, simulationType, - platforms, + platforms: selectedPlatforms, architecture, }, filters, }, onCompleted: (response) => { - setResult(response.obasContainerGenerateScenario); + setResult(response.obasContainerGenerateScenarioWithInjectPlaceholders); setIsSubmitting(false); handleClose(); }, @@ -276,7 +280,7 @@ const StixCoreObjectSimulationResult = ({ id, type }) => { interval, selection, simulationType, - platforms, + platforms: selectedPlatforms, architecture, }, filters, @@ -301,7 +305,7 @@ const StixCoreObjectSimulationResult = ({ id, type }) => { interval, selection, simulationType, - platforms, + platforms: selectedPlatforms, architecture, }, filters, @@ -389,46 +393,46 @@ const StixCoreObjectSimulationResult = ({ id, type }) => {
    {values.simulationType !== 'simulated' && ( - <> - {!hasAttackPatterns && ( - - {t_i18n('Technical (payloads) requires attack patterns in this entity.')} - - )} -
    - setPlatforms(newValue.map((option) => option.value))} - renderOption={(props, option) => ( -
  • -
    {option.label ?? ''}
    -
  • - )} - disabled={!hasAttackPatterns} - /> -
    -
    - setArchitecture(newValue)} - containerstyle={{ width: '100%' }} - > - x86_64 - arm64 - -
    - + <> + {!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 + +
    + )}
    { onChange={(_event, newValue) => setSelection(newValue)} containerstyle={{ width: '100%' }} > - {t_i18n('Multiple (limited to 5)')} {t_i18n('One (random)')} + {t_i18n('Multiple (limited to 5)')}
    @@ -640,21 +644,23 @@ const StixCoreObjectSimulationResult = ({ id, type }) => { } severity="success"> {t_i18n('The scenario has been correctly generated in your OpenBAS platform.')} - {result.attackPatternsWithoutInjectorContracts && result.attackPatternsWithoutInjectorContracts.trim() !== '' && ( - - {t_i18n('The following TTPs are not covered in your OpenBAS catalog : ')} -
      - {result.attackPatternsWithoutInjectorContracts.split(',').map((ttp, index) => ( -
    • {ttp}
    • - ))} -
    - {t_i18n('In response, we have created placeholders for these TTPs.')} -
    + {result.attackPatternsNotAvailableInOpenBAS && result.attackPatternsNotAvailableInOpenBAS.trim() !== '' && ( + + {t_i18n('The following TTPs are not covered in your OpenBAS catalog : ')} +
      + {result.attackPatternsNotAvailableInOpenBAS.split(',').map((ttp, index) => ( +
    • {ttp}
    • + ))} +
    + {result.hasInjectPlaceholders && ( + {t_i18n('In response, we have created placeholders for these TTPs.')} + )} +
    )}