From 813d2df3b98f08a8cd0b3b5e61c25dc2d597740e Mon Sep 17 00:00:00 2001 From: csuraparaju Date: Sat, 20 Apr 2024 22:34:24 -0400 Subject: [PATCH 01/11] dataSources shows up on UI --- nav-app/angular.json | 3 + nav-app/src/app/classes/filter.ts | 63 ++++++++++++++++++- nav-app/src/app/classes/view-model.ts | 16 +++++ .../app/datatable/data-table.component.html | 24 ++++--- package-lock.json | 6 ++ 5 files changed, 101 insertions(+), 11 deletions(-) create mode 100644 package-lock.json diff --git a/nav-app/angular.json b/nav-app/angular.json index dd5a16ba8..f504fac5c 100644 --- a/nav-app/angular.json +++ b/nav-app/angular.json @@ -142,5 +142,8 @@ "@schematics/angular:directive": { "prefix": "app" } + }, + "cli": { + "analytics": false } } diff --git a/nav-app/src/app/classes/filter.ts b/nav-app/src/app/classes/filter.ts index 7a665ec9f..1eae3079c 100644 --- a/nav-app/src/app/classes/filter.ts +++ b/nav-app/src/app/classes/filter.ts @@ -8,11 +8,21 @@ export class Filter { selection: string[]; }; + public dataSources : { + options: string[]; + selection: string[]; + } + constructor() { this.platforms = { selection: [], options: [], }; + + this.dataSources = { + selection: [], + options: [], + }; } /** @@ -27,6 +37,24 @@ export class Filter { } } + /** + * Initialize the data source options according to the data in the domain + * @param {Domain} domain the domain to parse for data source options + */ + + public initDataSourcesOptions(domain: Domain): void { + // dataSourcesMap is a Map + // We want to store the name field in the options array as well as the selection array + + // Iterate over the entries of the Map + for (const [key, value] of domain.dataSources.entries()) { + // Store the name field in the options array + this.dataSources.options.push(value.name); + this.dataSources.selection.push(value.name); + } + + } + /** * toggle the given value in the given filter * @param {*} filterName the name of the filter @@ -60,7 +88,7 @@ export class Filter { * @return stringified filter */ public serialize(): string { - return JSON.stringify({ platforms: this.platforms.selection }); + return JSON.stringify({ platforms: this.platforms.selection, dataSources: this.dataSources.selection }); } /** @@ -78,6 +106,25 @@ export class Filter { return true; }; + let isDataSourcesMap = function (obj: any): boolean { + // Check if obj is an instance of Map + if (!(obj instanceof Map)) { + return false; + } + + // Iterate over the entries of the Map + for (const [key, value] of obj.entries()) { + // Check if key is a string and value is an object with 'name' and 'external_references' properties + if (typeof key !== 'string' || typeof value !== 'object' || value === null || !('name' in value) || !('external_references' in value)) { + return false; + } + } + + return true; + } + + + // Deserialize platforms if (rep.platforms) { if (isStringArray(rep.platforms)) { let backwards_compatibility_mappings = { @@ -101,5 +148,19 @@ export class Filter { this.platforms.selection = Array.from(selection); } else console.error('TypeError: filter platforms field is not a string[]'); } + + // Deserialize data sources + + if(rep.dataSources) { + if (isDataSourcesMap(rep.dataSources)) { + this.dataSources.selection = Array.from(rep.dataSources.keys()); + // show debug message + console.log('Data Sources:', this.dataSources.selection); + // assert that selections is an array + if (!Array.isArray(this.dataSources.selection)) { + console.error('TypeError: filter dataSources selection field is not a string[]'); + } + } else console.error('TypeError: filter dataSources field is not a Map'); + } } } diff --git a/nav-app/src/app/classes/view-model.ts b/nav-app/src/app/classes/view-model.ts index b42f3bf32..9be8b64da 100644 --- a/nav-app/src/app/classes/view-model.ts +++ b/nav-app/src/app/classes/view-model.ts @@ -146,10 +146,12 @@ export class ViewModel { this.dataService.onDataLoad(this.domainVersionID, function () { self.initTechniqueVMs(); self.filters.initPlatformOptions(self.dataService.getDomain(self.domainVersionID)); + self.filters.initDataSourcesOptions(self.dataService.getDomain(self.domainVersionID)); }); } else { this.initTechniqueVMs(); this.filters.initPlatformOptions(domain); + this.filters.initDataSourcesOptions(domain); } this.loaded = true; } @@ -845,6 +847,20 @@ export class ViewModel { return true; //platform match } } + + // filter by data sources + let dataSources = new Set(technique.datasources); + for (let dataSource of this.filters.dataSources.selection) { + if (dataSources.has(dataSource)) { + techniqueVM.setIsVisible(true); + technique.subtechniques.forEach((subtechnique) => { + let subtechniqueVM = this.getTechniqueVM(subtechnique, tactic); + subtechniqueVM.setIsVisible(true); + }); + return true; // data source match + } + } + techniqueVM.setIsVisible(false); technique.subtechniques.forEach((subtechnique) => { let subtechniqueVM = this.getTechniqueVM(subtechnique, tactic); diff --git a/nav-app/src/app/datatable/data-table.component.html b/nav-app/src/app/datatable/data-table.component.html index e264caab8..c8de7f98f 100755 --- a/nav-app/src/app/datatable/data-table.component.html +++ b/nav-app/src/app/datatable/data-table.component.html @@ -1,3 +1,4 @@ + + +
+ -->
@@ -817,11 +821,11 @@ + -->
keyboard_arrow_up @@ -850,4 +854,4 @@
-
+
\ No newline at end of file diff --git a/package-lock.json b/package-lock.json new file mode 100644 index 000000000..a9cb9e746 --- /dev/null +++ b/package-lock.json @@ -0,0 +1,6 @@ +{ + "name": "attack-navigator", + "lockfileVersion": 3, + "requires": true, + "packages": {} +} From 55e654fe44f82f4952a77a714aa0f747ea1dc7d2 Mon Sep 17 00:00:00 2001 From: csuraparaju Date: Sat, 20 Apr 2024 23:20:49 -0400 Subject: [PATCH 02/11] datasource technique filter attempt --- nav-app/src/app/classes/filter.ts | 1 + nav-app/src/app/classes/view-model.ts | 15 ++++++++++----- 2 files changed, 11 insertions(+), 5 deletions(-) diff --git a/nav-app/src/app/classes/filter.ts b/nav-app/src/app/classes/filter.ts index 1eae3079c..4494dc7f4 100644 --- a/nav-app/src/app/classes/filter.ts +++ b/nav-app/src/app/classes/filter.ts @@ -31,6 +31,7 @@ export class Filter { */ public initPlatformOptions(domain: Domain): void { this.platforms.options = JSON.parse(JSON.stringify(domain.platforms)); + if (!this.platforms.selection.length) { // prevent overwriting current selection this.platforms.selection = JSON.parse(JSON.stringify(domain.platforms)); diff --git a/nav-app/src/app/classes/view-model.ts b/nav-app/src/app/classes/view-model.ts index 9be8b64da..8e245cda7 100644 --- a/nav-app/src/app/classes/view-model.ts +++ b/nav-app/src/app/classes/view-model.ts @@ -848,19 +848,24 @@ export class ViewModel { } } - // filter by data sources - let dataSources = new Set(technique.datasources); - for (let dataSource of this.filters.dataSources.selection) { - if (dataSources.has(dataSource)) { + // technique.datasources is a string of the datasource for + // the current technique. The string is of the form: + // 'Sensor Health: Host Status,File: File Metadata' + + let datasource = technique.datasources.split(':')[0]; + + for (let ds of this.filters.dataSources.selection) { + if (ds === datasource) { techniqueVM.setIsVisible(true); technique.subtechniques.forEach((subtechnique) => { let subtechniqueVM = this.getTechniqueVM(subtechnique, tactic); subtechniqueVM.setIsVisible(true); }); - return true; // data source match + return true; //datasource match } } + techniqueVM.setIsVisible(false); technique.subtechniques.forEach((subtechnique) => { let subtechniqueVM = this.getTechniqueVM(subtechnique, tactic); From f37ace8d7e5fd5ac708e3566ac3c2432f39bdaea Mon Sep 17 00:00:00 2001 From: csuraparaju Date: Mon, 22 Apr 2024 19:38:24 -0400 Subject: [PATCH 03/11] datasources filtering done --- nav-app/src/app/classes/filter.ts | 9 +++-- nav-app/src/app/classes/view-model.ts | 21 ++++++------ .../app/datatable/data-table.component.html | 34 ++++++++++++++----- 3 files changed, 42 insertions(+), 22 deletions(-) diff --git a/nav-app/src/app/classes/filter.ts b/nav-app/src/app/classes/filter.ts index 4494dc7f4..d69c100a6 100644 --- a/nav-app/src/app/classes/filter.ts +++ b/nav-app/src/app/classes/filter.ts @@ -71,8 +71,7 @@ export class Filter { this[filterName].selection.splice(index, 1); } else { this[filterName].selection.push(value); - } - } + } } /** * determine if the given value is active in the filter @@ -116,7 +115,11 @@ export class Filter { // Iterate over the entries of the Map for (const [key, value] of obj.entries()) { // Check if key is a string and value is an object with 'name' and 'external_references' properties - if (typeof key !== 'string' || typeof value !== 'object' || value === null || !('name' in value) || !('external_references' in value)) { + if (typeof key !== 'string' || + typeof value !== 'object' || + value === null || + !('name' in value) || + !('external_references' in value)) { return false; } } diff --git a/nav-app/src/app/classes/view-model.ts b/nav-app/src/app/classes/view-model.ts index 8e245cda7..22d0c5dbb 100644 --- a/nav-app/src/app/classes/view-model.ts +++ b/nav-app/src/app/classes/view-model.ts @@ -819,6 +819,9 @@ export class ViewModel { return techniques.filter((technique: Technique) => { let techniqueVM = this.getTechniqueVM(technique, tactic); // filter by enabled + let in_platform = false; + let in_ds = false; + if (this.hideDisabled && !this.isSubtechniqueEnabled(technique, techniqueVM, tactic)) { techniqueVM.setIsVisible(false); technique.subtechniques.forEach((subtechnique) => { @@ -844,34 +847,32 @@ export class ViewModel { let subtechniqueVM = this.getTechniqueVM(subtechnique, tactic); subtechniqueVM.setIsVisible(true); }); - return true; //platform match + in_platform = true; } } - // technique.datasources is a string of the datasource for - // the current technique. The string is of the form: - // 'Sensor Health: Host Status,File: File Metadata' - - let datasource = technique.datasources.split(':')[0]; + let ds_mid = technique.datasources.split(',').map((ds) => ds.split(':')[0]); + let datasources = new Set(ds_mid); for (let ds of this.filters.dataSources.selection) { - if (ds === datasource) { + if (datasources.has(ds)) { techniqueVM.setIsVisible(true); technique.subtechniques.forEach((subtechnique) => { let subtechniqueVM = this.getTechniqueVM(subtechnique, tactic); subtechniqueVM.setIsVisible(true); }); - return true; //datasource match + in_ds = true; } } - techniqueVM.setIsVisible(false); technique.subtechniques.forEach((subtechnique) => { let subtechniqueVM = this.getTechniqueVM(subtechnique, tactic); subtechniqueVM.setIsVisible(false); }); - return false; // no platform match + + return in_platform && in_ds; + }); } diff --git a/nav-app/src/app/datatable/data-table.component.html b/nav-app/src/app/datatable/data-table.component.html index c8de7f98f..55ad4ce01 100755 --- a/nav-app/src/app/datatable/data-table.component.html +++ b/nav-app/src/app/datatable/data-table.component.html @@ -269,23 +269,39 @@ filter_list