Skip to content

Commit

Permalink
merging in multiselect
Browse files Browse the repository at this point in the history
  • Loading branch information
isaisabel committed Jun 23, 2021
2 parents 0c4667b + b19f767 commit 8819266
Show file tree
Hide file tree
Showing 29 changed files with 578 additions and 482 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
# v4.4 - Changes staged on Develop
## Improvements
- Combined the search and multiselect interfaces into a single UI. This allows groups, software, and mitigations to be filtered alongside techniques and improves usability by moving the interface to a sidebar. See issue [#204](https://github.com/mitre-attack/attack-navigator/issues/204).
- Improved favicon for standardization with other ATT&CK tools.

## Fixes
Expand Down
13 changes: 1 addition & 12 deletions nav-app/src/app/app.component.html
Original file line number Diff line number Diff line change
@@ -1,13 +1,2 @@
<!--The content below is only a placeholder and can be replaced.-->
<!-- <div *ngIf="techniques && tactics"> -->
<tabs>
<!-- <tab [tabTitle]="'grid'">
<DataTable></DataTable>
</tab> -->
</tabs>
<tabs></tabs>
<span style="font-size: 7pt">MITRE ATT&CK&reg; Navigator v{{nav_version}}</span>

<!-- </div> -->
<!-- <div *ngIf="!techniques && !tactics">
loading...
</div> -->
3 changes: 1 addition & 2 deletions nav-app/src/app/app.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { Component, ViewChild, DoCheck, HostListener } from '@angular/core';
import { TabsComponent } from './tabs/tabs.component';
import { ConfigService } from './config.service';
import * as globals from "./globals";
import { DataService } from './data.service';

@Component({
selector: 'app-root',
Expand Down Expand Up @@ -30,6 +31,4 @@ export class AppComponent {
return false;
}
}


}
15 changes: 11 additions & 4 deletions nav-app/src/app/app.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@ import { MatCheckboxModule } from '@angular/material/checkbox';
import { MatDialogModule } from '@angular/material/dialog';
import { MatMenuModule } from '@angular/material/menu';
import { MatExpansionModule } from '@angular/material/expansion';
import { MatSidenavModule } from '@angular/material/sidenav';

import { ColorPickerModule } from 'ngx-color-picker';
import { HttpClientModule } from '@angular/common/http';

Expand All @@ -27,11 +29,13 @@ import { MatrixSideComponent } from './matrix/matrix-side/matrix-side.component'
import { MatrixFlatComponent } from './matrix//matrix-flat/matrix-flat.component';
import { MatrixMiniComponent } from './matrix//matrix-mini/matrix-mini.component';
import { TooltipComponent } from './matrix/technique-cell/tooltip/tooltip.component';
import { MultiselectComponent } from './multiselect/multiselect.component';
import { TechniquesSearchComponent } from './techniques-search/techniques-search.component';
import { SearchAndMultiselectComponent } from './search-and-multiselect/search-and-multiselect.component';
import { ContextmenuComponent } from './matrix/technique-cell/contextmenu/contextmenu.component';
import { TacticCellComponent } from './matrix/tactic-cell/tactic-cell.component';
import { VersionUpgradeComponent } from './version-upgrade/version-upgrade.component';
import { SidebarComponent } from './sidebar/sidebar.component';
import { MatCardModule } from "@angular/material/card";
import { MatDividerModule } from "@angular/material/divider";


@NgModule({
Expand All @@ -46,11 +50,11 @@ import { VersionUpgradeComponent } from './version-upgrade/version-upgrade.compo
MatrixFlatComponent,
MatrixMiniComponent,
TooltipComponent,
MultiselectComponent,
TechniquesSearchComponent,
SearchAndMultiselectComponent,
ContextmenuComponent,
TacticCellComponent,
VersionUpgradeComponent,
SidebarComponent
],
imports: [
BrowserModule,
Expand All @@ -68,6 +72,9 @@ import { VersionUpgradeComponent } from './version-upgrade/version-upgrade.compo
MatExpansionModule,
MatDialogModule,
ColorPickerModule,
MatSidenavModule,
MatCardModule,
MatDividerModule
],
exports: [
MatSelectModule,
Expand Down
37 changes: 23 additions & 14 deletions nav-app/src/app/data.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -43,15 +43,23 @@ export class DataService {
*/
parseBundle(domain: Domain, stixBundles: any[]): void {
let platforms = new Set<String>();
let seenIDs = new Set<String>();
for (let bundle of stixBundles) {
let techniqueSDOs = [];
let matrixSDOs = [];
let idToTechniqueSDO = new Map<string, any>();
let idToTacticSDO = new Map<string, any>();
for (let sdo of bundle.objects) { //iterate through stix domain objects in the bundle
// ignore deprecated and revoked objects in the bundle
if (sdo.x_mitre_deprecated || sdo.revoked) continue;
if ("x_mitre_domains" in sdo && !sdo.x_mitre_domains.includes(domain.domain_identifier)) continue; //object not included in this domain
// ignore deprecated and revoked objects in the bundle?
if (sdo.x_mitre_deprecated || sdo.revoked) continue;

// Filter out object not included in this domain if domains field is available
if ("x_mitre_domains" in sdo && !sdo.x_mitre_domains.includes(domain.domain_identifier)) continue;

// filter out duplicates
if (!seenIDs.has(sdo.id)) seenIDs.add(sdo.id)
else continue;

// parse according to type
switch(sdo.type) {
case "intrusion-set":
Expand Down Expand Up @@ -134,16 +142,18 @@ export class DataService {
}
domain.techniques.push(new Technique(techniqueSDO, subtechniques, this));
}

//create matrices, which also creates tactics and filters techniques
for (let matrixSDO of matrixSDOs) {
domain.matrices.push(new Matrix(matrixSDO, idToTacticSDO, domain.techniques, this));
}

// parse platforms
for (let technique of domain.techniques) {
for (let platform of technique.platforms) {
platforms.add(platform)
if (technique.platforms) {
for (let platform of technique.platforms) {
platforms.add(platform)
}
}
}
for (let subtechnique of domain.subtechniques) {
Expand Down Expand Up @@ -303,9 +313,9 @@ export class DataService {
}
}

/**
/**
* Common attributes for STIX objects
*/
*/
export abstract class BaseStix {
public readonly id: string; // STIX ID
public readonly attackID: string; // ATT&CK ID
Expand Down Expand Up @@ -377,15 +387,14 @@ export class Technique extends BaseStix {
this.platforms = stixSDO.x_mitre_platforms;
if (stixSDO.x_mitre_data_sources !== undefined)
this.datasources = stixSDO.x_mitre_data_sources.toString();
else
else
this.datasources = "";
this.tactics = stixSDO.kill_chain_phases.map((phase) => phase.phase_name);

this.subtechniques = subtechniques;
for (let subtechnique of this.subtechniques) {
subtechnique.parent = this;
}

}

/**
Expand Down Expand Up @@ -473,7 +482,7 @@ export class Mitigation extends BaseStix {
let rels = this.dataService.getDomain(domainID).relationships.mitigates;
if (rels.has(this.id)) {
return rels.get(this.id);
}
}
else return [];
}
/**
Expand Down Expand Up @@ -528,10 +537,10 @@ export class Domain {
public relationships: any = {
// subtechnique subtechnique-of technique
// ID of technique to [] of subtechnique IDs
subtechniques_of: new Map<string, string[]>(),
subtechniques_of: new Map<string, string[]>(),
// group uses technique
// ID of group to [] of technique IDs
group_uses: new Map<string, string[]>(),
group_uses: new Map<string, string[]>(),
// group uses technique
// ID of group to [] of technique IDs
software_uses: new Map<string, string[]>(),
Expand Down
63 changes: 26 additions & 37 deletions nav-app/src/app/datatable/data-table.component.html
Original file line number Diff line number Diff line change
Expand Up @@ -40,33 +40,14 @@
<!-- Search -->
<div *ngIf="configService.getFeature('search')" class="control-row-item">

<div class="control-row-button dropdown noselect"
(click)="currentDropdown = currentDropdown !== 'search' ? 'search' : null;"
<div class="control-row-button noselect"
(click)="(viewModel.sidebarOpened = (viewModel.sidebarContentType !== 'search') ? true : !viewModel.sidebarOpened) && (viewModel.sidebarContentType = 'search')"
matTooltipPosition="below"
matTooltip="search">
matTooltip="search & multiselect">
<img src="assets/icons/ic_search_black_24px.svg"/>
</div>

<div class="dropdown-container search" *ngIf="currentDropdown === 'search'" #dropdown [class.left]="checkalign(dropdown)">
<app-techniques-search [viewModel]="viewModel"></app-techniques-search>
</div>
</div>


<!-- Multi-select -->
<div *ngIf="configService.getFeature('multiselect')" class="control-row-item">
<div class="control-row-button dropdown noselect"
(click)="currentDropdown = currentDropdown !== 'multiselect' ? 'multiselect' : null;"
matTooltipPosition="below"
matTooltip="multi-select">
<img src="assets/icons/ic_playlist_add_black_24px.svg"/>
</div>
<div class="dropdown-container multiselect" *ngIf="currentDropdown === 'multiselect'" #dropdown [class.left]="checkalign(dropdown)">
<app-multiselect [viewModel]="viewModel"></app-multiselect>
</div>
</div>


<!-- deselect all -->
<div *ngIf="configService.getFeature('deselect_all')" class="control-row-item">
<div class="control-row-button noselect"
Expand Down Expand Up @@ -535,26 +516,34 @@
88 888 88 8oooo88 888 888 88o 888 88 888
o88o 8 o88o o88o o888o o888o o888o 88o8 o888o o88o o888o
-->

<div class="matrices" oncontextmenu="return false">
<div class="matrices">
<div oncontextmenu="return false">
<div class="spinner" *ngIf="!dataService.getDomain(viewModel.domainID).dataLoaded">
<mat-progress-spinner mode="indeterminate"></mat-progress-spinner>
</div>
<div class="matrices-columns">
<div class="matrix-column" *ngFor="let matrix of dataService.getDomain(viewModel.domainID).matrices">
<div *ngIf="dataService.getDomain(viewModel.domainID).matrices.length > 1" class="matrix-name">{{matrix.name}}</div>
<div *ngIf="viewModel.layout.layout == 'side'">
<matrix-side [matrix]="matrix" [viewModel]="viewModel" (selectionChanged)="onTechniqueSelect()"></matrix-side>
</div>
<div *ngIf="viewModel.layout.layout == 'flat'">
<matrix-flat [matrix]="matrix" [viewModel]="viewModel" (selectionChanged)="onTechniqueSelect()"></matrix-flat>
</div>
<div *ngIf="viewModel.layout.layout == 'mini'">
<matrix-mini [matrix]="matrix" [viewModel]="viewModel" (selectionChanged)="onTechniqueSelect()"></matrix-mini>
<mat-drawer-container autosize>
<mat-drawer-content>
<div class="matrices-columns">
<div class="matrix-column" *ngFor="let matrix of dataService.getDomain(viewModel.domainID).matrices">
<div *ngIf="dataService.getDomain(viewModel.domainID).matrices.length > 1" class="matrix-name">{{matrix.name}}</div>
<div *ngIf="viewModel.layout.layout == 'side'">
<matrix-side [matrix]="matrix" [viewModel]="viewModel" (selectionChanged)="onTechniqueSelect()"></matrix-side>
</div>
<div *ngIf="viewModel.layout.layout == 'flat'">
<matrix-flat [matrix]="matrix" [viewModel]="viewModel" (selectionChanged)="onTechniqueSelect()"></matrix-flat>
</div>
<div *ngIf="viewModel.layout.layout == 'mini'">
<matrix-mini [matrix]="matrix" [viewModel]="viewModel" (selectionChanged)="onTechniqueSelect()"></matrix-mini>
</div>
</div>
</div>
</div>
</div>
</mat-drawer-content>
<mat-drawer mode="side" position="end" #sidebar [opened]="viewModel.sidebarOpened">
<sidebar [viewModel]="viewModel"></sidebar>
</mat-drawer>
</mat-drawer-container>
</div>
</div>


<!--
Expand Down
2 changes: 1 addition & 1 deletion nav-app/src/app/datatable/data-table.component.scss
Original file line number Diff line number Diff line change
Expand Up @@ -405,6 +405,7 @@ $panel-light: lighten($panel-dark, 8%);
}

.legendBar {
z-index: 999;
position: fixed;
bottom: 0;
right: 0;
Expand Down Expand Up @@ -472,4 +473,3 @@ $panel-light: lighten($panel-dark, 8%);
}
}
}

19 changes: 9 additions & 10 deletions nav-app/src/app/datatable/data-table.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ declare var tinycolor: any; //use tinycolor2

import * as FileSaver from 'file-saver';
import { ColorPickerModule } from 'ngx-color-picker';
import { TechniquesSearchComponent } from '../techniques-search/techniques-search.component';
import { SearchAndMultiselectComponent } from '../search-and-multiselect/search-and-multiselect.component';
import { TmplAstVariable } from '@angular/compiler';

@Component({
Expand All @@ -37,7 +37,6 @@ export class DataTableComponent implements AfterViewInit {

currentDropdown: string = ""; //current dropdown menu


//////////////////////////////////////////////////////////
// Stringifies the current view model into a json string//
// stores the string as a blob //
Expand All @@ -50,7 +49,7 @@ export class DataTableComponent implements AfterViewInit {
let filename = this.viewModel.name.replace(/ /g, "_") + ".json";
// FileSaver.saveAs(blob, this.viewModel.name.replace(/ /g, "_") + ".json");
this.saveBlob(blob, filename);

}

saveBlob(blob, filename){
Expand All @@ -75,8 +74,8 @@ export class DataTableComponent implements AfterViewInit {
var workbook = new Excel.Workbook();
let domain = this.dataService.getDomain(this.viewModel.domainID);
for (let matrix of domain.matrices) {
var worksheet = workbook.addWorksheet(matrix.name + " (v" + domain.getVersion() + ")");
var worksheet = workbook.addWorksheet(matrix.name + " (v" + domain.getVersion() + ")");

// create tactic columns
let columns = this.viewModel.filterTactics(matrix.tactics, matrix).map(tactic => { return {header: this.getDisplayName(tactic), key: tactic.name} });
worksheet.columns = columns;
Expand Down Expand Up @@ -234,10 +233,10 @@ export class DataTableComponent implements AfterViewInit {
}
}

constructor(public dataService: DataService,
private tabs: TabsComponent,
private sanitizer: DomSanitizer,
private viewModelsService: ViewModelsService,
constructor(public dataService: DataService,
private tabs: TabsComponent,
private sanitizer: DomSanitizer,
private viewModelsService: ViewModelsService,
public configService: ConfigService) { }

/**
Expand Down Expand Up @@ -273,7 +272,7 @@ export class DataTableComponent implements AfterViewInit {
* @param addToSelection add to the technique selection (shift key) or replace selection?
*/
onTechniqueSelect(technique, addToSelection, eventX, eventY): void {

if (!this.viewModel.isCurrentlyEditing()) {
if (["comment", "score", "colorpicker"].includes(this.currentDropdown)) this.currentDropdown = ""; //remove technique control dropdowns, because everything was deselected
return;
Expand Down
Loading

0 comments on commit 8819266

Please sign in to comment.