Skip to content

Commit

Permalink
merging in develop
Browse files Browse the repository at this point in the history
  • Loading branch information
isaisabel committed Oct 21, 2021
2 parents 9a9764c + bb7c6ee commit 899df56
Show file tree
Hide file tree
Showing 83 changed files with 1,970 additions and 496 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -32,3 +32,4 @@ Temporary Items
# End of https://www.toptal.com/developers/gitignore/api/macos

*.env
.vscode
2 changes: 1 addition & 1 deletion app/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion app/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "attack-workbench-frontend",
"version": "1.0.2",
"version": "1.0.3",
"description": "An application allowing users to explore, create, annotate, and share extensions of the MITRE ATT&CK® knowledge base. This repository contains an Angular-based web application providing the user interface for the ATT&CK Workbench application.",
"keywords": [
"cti",
Expand Down
50 changes: 49 additions & 1 deletion app/src/app/app-routing-stix.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import { NgModule } from '@angular/core';
import { environment } from "../environments/environment"
import { CollectionImportComponent } from "./views/stix/collection/collection-import/collection-import-workflow/collection-import.component";
import { CollectionIndexImportComponent } from "./views/stix/collection/collection-index/collection-index-import/collection-index-import.component";
import { DataSourceListComponent } from "./views/stix/data-source/data-source-list/data-source-list.component";

const stixRoutes: Routes = [{
path: 'matrix',
Expand Down Expand Up @@ -294,7 +295,54 @@ const stixRoutes: Routes = [{
}
]
},

{
path: 'data-source',
data: {
breadcrumb: 'data sources'
},
children: [{
path: '',
data: {
breadcrumb: 'list',
title: "data sources"
},
component: DataSourceListComponent
},
{
path: ':id',
data: {
breadcrumb: 'loading...'
},
children: [{
path: '',
data: {
breadcrumb: 'view',
editable: true,
title: "view data source"
},
component: StixPageComponent
}
]
},
{
path: ":new",
data: {
breadcrumb: "new data source"
},
children: [{
path: '',
data: {
breadcrumb: 'view',
editable: true,
title: "new data source"
},
component: StixPageComponent
}
]
}
]
},

]

if (environment.integrations.collection_manager.enabled) {
Expand Down
10 changes: 6 additions & 4 deletions app/src/app/app.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -51,15 +51,17 @@ export class AppComponent implements AfterViewInit {

// header hiding with scroll
ngAfterViewInit() {
this.scrollRef.nativeElement.addEventListener('scroll', (e) => this.scrollEvent(), true);
this.scrollRef.nativeElement.addEventListener('scroll', (e) => this.adjustHeaderPlacement(), true);
//to fix rare cases that the page has resized without scroll events triggering, recompute the offset every 5 seconds
setInterval(() => this.adjustHeaderPlacement(), 5000);
}
ngOnDestroy() {
this.scrollRef.nativeElement.removeEventListener('scroll', (e) => this.scrollEvent(), true);
this.scrollRef.nativeElement.removeEventListener('scroll', (e) => this.adjustHeaderPlacement(), true);
}

public hiddenHeaderPX: number = 0; //number of px of the header which is hidden
// when a scroll happens
private scrollEvent(): void {
// adjust the header placement
private adjustHeaderPlacement(): void {
let headerHeight = this.header.nativeElement.offsetHeight;
// constrain amount of hidden to bounds, round up because decimal scroll causes flicker
this.hiddenHeaderPX = Math.floor(Math.min(Math.max(0, this.scrollRef.nativeElement.scrollTop/2), headerHeight));
Expand Down
13 changes: 11 additions & 2 deletions app/src/app/app.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -114,11 +114,13 @@ import { CollectionManagerComponent } from "./views/stix/collection/collection-m
import { CollectionIndexListComponent } from "./views/stix/collection/collection-index/collection-index-list/collection-index-list.component";
import { CollectionIndexViewComponent } from "./views/stix/collection/collection-index/collection-index-view/collection-index-view.component";
import { CollectionIndexImportComponent } from "./views/stix/collection/collection-index/collection-index-import/collection-index-import.component";
import { CollectionImportReviewComponent } from "./views/stix/collection/collection-import/collection-import-review/collection-import-review.component";

import { CollectionListComponent } from './views/stix/collection/collection-list/collection-list.component';
import { CollectionViewComponent } from './views/stix/collection/collection-view/collection-view.component';
import { CollectionImportComponent } from './views/stix/collection/collection-import/collection-import-workflow/collection-import.component';
import { CollectionImportReviewComponent } from "./views/stix/collection/collection-import/collection-import-review/collection-import-review.component";
import { CollectionImportErrorComponent } from './views/stix/collection/collection-import/collection-import-error/collection-import-error.component';

// import { CollectionExportComponent } from './views/stix/collection/collection-export/collection-export.component';

import { GroupViewComponent } from './views/stix/group/group-view/group-view.component';
Expand Down Expand Up @@ -153,6 +155,9 @@ import { ObjectStatusComponent } from './components/object-status/object-status.
import { IconViewComponent } from './components/stix/icon-view/icon-view.component';
import { IdentityPropertyComponent } from './components/stix/identity-property/identity-property.component';
import { NgxJdenticonModule, JDENTICON_CONFIG } from 'ngx-jdenticon';
import { DataSourceViewComponent } from './views/stix/data-source/data-source-view/data-source-view.component';
import { DataSourceListComponent } from './views/stix/data-source/data-source-list/data-source-list.component';
import { DataComponentViewComponent } from './views/stix/data-component/data-component-view/data-component-view.component';


@NgModule({
Expand Down Expand Up @@ -218,6 +223,7 @@ import { NgxJdenticonModule, JDENTICON_CONFIG } from 'ngx-jdenticon';
CollectionIndexImportComponent,
CollectionImportComponent,
CollectionImportReviewComponent,
CollectionImportErrorComponent,
// CollectionExportComponent,

RelationshipViewComponent,
Expand Down Expand Up @@ -249,7 +255,10 @@ import { NgxJdenticonModule, JDENTICON_CONFIG } from 'ngx-jdenticon';

NotesEditorComponent,
ObjectStatusComponent,
IdentityPropertyComponent
IdentityPropertyComponent,
DataSourceViewComponent,
DataSourceListComponent,
DataComponentViewComponent
],
imports: [
BreadcrumbModule,
Expand Down
41 changes: 27 additions & 14 deletions app/src/app/classes/stix/collection.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ import { Software } from './software';
import { StixObject } from './stix-object';
import { Tactic } from './tactic';
import { Technique } from './technique';
import { DataSource } from './data-source';
import { DataComponent } from './data-component';
import { logger } from "../../util/logger";

/**
Expand Down Expand Up @@ -164,6 +166,7 @@ export class Collection extends StixObject {
// each sub-property is a list of STIX IDs corresponding to objects in the import
public import_categories: CollectionDiffCategories<string>;

public readonly supportsAttackID = false; // collections do not support ATT&CK IDs
protected get attackIDValidator() { return null; } //collections do not have ATT&CK IDs

constructor(sdo?: any) {
Expand Down Expand Up @@ -279,6 +282,12 @@ export class Collection extends StixObject {
case "intrusion-set": //group
this.stix_contents.push(new Group(obj))
break;
case "x-mitre-data-source": // data source
this.stix_contents.push(new DataSource(obj))
break;
case "x-mitre-data-component": // data component
this.stix_contents.push(new DataComponent(obj))
break;
}
}
}
Expand All @@ -289,22 +298,26 @@ export class Collection extends StixObject {
* @memberof Collection
*/
public compareTo(that: Collection): {
technique: CollectionDiffCategories<Technique>,
tactic: CollectionDiffCategories<Tactic>,
software: CollectionDiffCategories<Software>,
relationship: CollectionDiffCategories<Relationship>,
mitigation: CollectionDiffCategories<Mitigation>,
matrix: CollectionDiffCategories<Matrix>,
group: CollectionDiffCategories<Group>
technique: CollectionDiffCategories<Technique>,
tactic: CollectionDiffCategories<Tactic>,
software: CollectionDiffCategories<Software>,
relationship: CollectionDiffCategories<Relationship>,
mitigation: CollectionDiffCategories<Mitigation>,
matrix: CollectionDiffCategories<Matrix>,
group: CollectionDiffCategories<Group>,
data_source: CollectionDiffCategories<DataSource>,
data_component: CollectionDiffCategories<DataComponent>
} {
let results = {
technique: new CollectionDiffCategories<Technique>(),
tactic: new CollectionDiffCategories<Tactic>(),
software: new CollectionDiffCategories<Software>(),
relationship: new CollectionDiffCategories<Relationship>(),
mitigation: new CollectionDiffCategories<Mitigation>(),
matrix: new CollectionDiffCategories<Matrix>(),
group: new CollectionDiffCategories<Group>()
technique: new CollectionDiffCategories<Technique>(),
tactic: new CollectionDiffCategories<Tactic>(),
software: new CollectionDiffCategories<Software>(),
relationship: new CollectionDiffCategories<Relationship>(),
mitigation: new CollectionDiffCategories<Mitigation>(),
matrix: new CollectionDiffCategories<Matrix>(),
group: new CollectionDiffCategories<Group>(),
data_source: new CollectionDiffCategories<DataSource>(),
data_component: new CollectionDiffCategories<DataComponent>()
}
// build helper lookups to reduce complexity from n^2 to n.
let thisStixLookup = new Map<string, StixObject>(this.stix_contents.map(sdo => [sdo.stixID, sdo]))
Expand Down
98 changes: 98 additions & 0 deletions app/src/app/classes/stix/data-component.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
import { Observable } from "rxjs";
import { RestApiConnectorService } from "src/app/services/connectors/rest-api/rest-api-connector.service";
import { ValidationData } from "../serializable";
import { StixObject } from "./stix-object";
import { logger } from "../../util/logger";
import { DataSource } from "./data-source";

export class DataComponent extends StixObject {
public name: string = "";
public description: string = "";
public domains: string[] = ['enterprise-attack']; // default to enterprise
public data_source_ref: string; // stix ID of the data source

// NOTE: the following field will only be populated when this object is fetched using getDataComponent()
public data_source: DataSource = null;

public readonly supportsAttackID = false; // data components do not support ATT&CK IDs
protected get attackIDValidator() { return null; } // data components have no ATT&CK ID

constructor(sdo?: any) {
super(sdo, "x-mitre-data-component");
if (sdo) {
this.deserialize(sdo);
}
}

/**
* Transform the current object into a raw object for sending to the back-end
* @abstract
* @returns {*} the raw object to send
*/
public serialize(): any {
let rep = super.base_serialize();

rep.stix.name = this.name;
rep.stix.description = this.description;
rep.stix.x_mitre_data_source_ref = this.data_source_ref;
rep.stix.x_mitre_domains = this.domains;

return rep;
}

/**
* Parse the object from the record returned from the back-end
* @abstract
* @param {*} raw the raw object to parse
*/
public deserialize(raw: any) {
if (!("stix" in raw)) return;

let sdo = raw.stix;

if ("name" in sdo) {
if (typeof(sdo.name) === "string") this.name = sdo.name;
else logger.error("TypeError: name field is not a string:", sdo.name, "(",typeof(sdo.name),")")
} else this.name = "";

if ("description" in sdo) {
if (typeof(sdo.description) === "string") this.description = sdo.description;
else logger.error("TypeError: description field is not a string:", sdo.description, "(",typeof(sdo.description),")")
} else this.description = "";

if ("x_mitre_data_source_ref" in sdo) {
if (typeof(sdo.x_mitre_data_source_ref) === "string") this.data_source_ref = sdo.x_mitre_data_source_ref;
else logger.error("TypeError: data source ref field is not a string:", sdo.x_mitre_data_source_ref, "(",typeof(sdo.x_mitre_data_source_ref),")")
} else this.data_source_ref = "";

if ("x_mitre_domains" in sdo) {
if (this.isStringArray(sdo.x_mitre_domains)) this.domains = sdo.x_mitre_domains;
else logger.error("TypeError: domains field is not a string array.");
} else this.domains = ['enterprise-attack']; // default to enterprise
}

/**
* Validate the current object state and return information on the result of the validation
* @param {RestApiConnectorService} restAPIService: the REST API connector through which asynchronous validation can be completed
* @returns {Observable<ValidationData>} the validation warnings and errors once validation is complete.
*/
public validate(restAPIService: RestApiConnectorService): Observable<ValidationData> {
return this.base_validate(restAPIService);
}

/**
* Save the current state of the STIX object in the database. Update the current object from the response
* @param restAPIService [RestApiConnectorService] the service to perform the POST/PUT through
* @returns {Observable} of the post
*/
public save(restAPIService: RestApiConnectorService): Observable<DataComponent> {
// TODO POST if the object was just created (doesn't exist in db yet)

let postObservable = restAPIService.postDataComponent(this);
let subscription = postObservable.subscribe({
next: (result) => { this.deserialize(result.serialize()); },
complete: () => { subscription.unsubscribe(); }
});
return postObservable;
}
}
Loading

0 comments on commit 899df56

Please sign in to comment.