Skip to content

Commit

Permalink
Refactor ConfigService (#615)
Browse files Browse the repository at this point in the history
* load configuration on startup

* better variable names

* remove unused functions

* additional small refactor

* update tests

* fix data service tests

* update config service tests

* more test updates

* fixed broken tests

* ran prettier autoformatter

* duplication fixes

* fix code smells
  • Loading branch information
clemiller authored Feb 20, 2024
1 parent fffd3a7 commit 19aa107
Show file tree
Hide file tree
Showing 16 changed files with 1,254 additions and 1,353 deletions.
6 changes: 6 additions & 0 deletions nav-app/src/app/app.component.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import { deleteCookie, getCookie, hasCookie, setCookie } from './utils/cookies';
import { TabsComponent } from './tabs/tabs.component';
import { MatDialogModule } from '@angular/material/dialog';
import { MatSnackBarModule } from '@angular/material/snack-bar';
import { ConfigService } from './services/config.service';

describe('AppComponent', () => {
let fixture: ComponentFixture<AppComponent>;
Expand All @@ -15,6 +16,11 @@ describe('AppComponent', () => {
imports: [HttpClientTestingModule, MatDialogModule, MatSnackBarModule],
declarations: [AppComponent, TabsComponent],
}).compileComponents();

// set up config service
let configService = TestBed.inject(ConfigService);
configService.defaultLayers = { enabled: false };

fixture = TestBed.createComponent(AppComponent);
app = fixture.debugElement.componentInstance;
}));
Expand Down
16 changes: 14 additions & 2 deletions nav-app/src/app/app.module.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { BrowserModule, Title } from '@angular/platform-browser';
import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
import { NgModule } from '@angular/core';
import { APP_INITIALIZER, NgModule } from '@angular/core';
import 'rxjs/add/operator/map';

// material
Expand Down Expand Up @@ -49,6 +49,7 @@ import { LayerInformationComponent } from './layer-information/layer-information
import { ChangelogComponent } from './changelog/changelog.component';
import { MatTabsModule } from '@angular/material/tabs';
import { ListInputComponent } from './list-input/list-input.component';
import { ConfigService } from './services/config.service';

@NgModule({
declarations: [
Expand Down Expand Up @@ -102,7 +103,18 @@ import { ListInputComponent } from './list-input/list-input.component';
MatTabsModule,
],
exports: [MatSelectModule, MatInputModule, MatButtonModule, MatIconModule, MatTooltipModule, MatMenuModule, MatExpansionModule, MatTabsModule],
providers: [Title],
providers: [
Title,
ConfigService,
{
provide: APP_INITIALIZER,
useFactory: (configService: ConfigService) => {
return () => configService.loadConfig();
},
deps: [ConfigService],
multi: true,
},
],
bootstrap: [AppComponent],
})
export class AppModule {}
Original file line number Diff line number Diff line change
@@ -1,15 +1,15 @@
<div class="technique-cell" [ngStyle]="getTechniqueBackground()" [ngClass]="getClass()">
<div (click)="onClick()" (mouseenter)="highlight()" (mouseleave)="unhighlight()">
<div class="section">
<span [style.border-color]="configService.comment_color" [style.color]="getTechniqueTextColor()">
<span [style.border-color]="configService.commentColor" [style.color]="getTechniqueTextColor()">
<b>{{ tactic.name }}</b>
</span>
</div>
<div class="section">
<span [style.border-color]="configService.comment_color" [style.color]="getTechniqueTextColor()">{{ technique.attackID }}</span>
<span [style.border-color]="configService.commentColor" [style.color]="getTechniqueTextColor()">{{ technique.attackID }}</span>
</div>
<div class="section">
<span [style.border-color]="configService.comment_color" [style.color]="getTechniqueTextColor()">{{ technique.name }}</span>
<span [style.border-color]="configService.commentColor" [style.color]="getTechniqueTextColor()">{{ technique.name }}</span>
</div>
</div>
</div>
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,13 @@ import { Link, Metadata, TechniqueVM, ViewModel } from '../../classes';
import { Note, Tactic, Technique } from '../../classes/stix';
import tinycolor from 'tinycolor2';
import { deleteCookie, hasCookie } from '../../utils/cookies';
import { ConfigService } from '../../services/config.service';
import * as MockData from '../../../tests/utils/mock-data';

describe('ChangelogCellComponent', () => {
let component: ChangelogCellComponent;
let fixture: ComponentFixture<ChangelogCellComponent>;
let configService: ConfigService;
let technique_list: Technique[] = [];
let stixSDO = {
name: 'Name',
Expand Down Expand Up @@ -65,27 +68,16 @@ describe('ChangelogCellComponent', () => {
imports: [HttpClientTestingModule],
declarations: [ChangelogCellComponent],
}).compileComponents();
});

beforeEach(() => {
// set up config service
configService = TestBed.inject(ConfigService);
configService.versions = MockData.configData;

fixture = TestBed.createComponent(ChangelogCellComponent);
component = fixture.debugElement.componentInstance;
let versions = [
{
name: 'ATT&CK v13',
version: '13',
domains: [
{
name: 'Enterprise',
identifier: 'enterprise-attack',
data: ['https://raw.githubusercontent.com/mitre/cti/ATT%26CK-v13.1/enterprise-attack/enterprise-attack.json'],
},
],
},
];
component.dataService.setUpURLs(versions);
component.configService.setFeature('aggregate_score_color', true);
component.configService.setFeature('non_aggregate_score_color', true);

configService.setFeature('aggregate_score_color', true);
configService.setFeature('non_aggregate_score_color', true);
component.viewModel = new ViewModel('layer', '33', 'enterprise-attack-13', null);
component.viewModel.domainVersionID = 'enterprise-attack-13';
let st1 = new Technique(subtechniqueSDO1, [], null);
Expand Down Expand Up @@ -160,7 +152,7 @@ describe('ChangelogCellComponent', () => {
component.viewModel.layout._showAggregateScores = true;
expect(component.getTechniqueBackground()).toEqual({ background: component.emulate_alpha('black') });
component.viewModel.getTechniqueVM(component.technique, component.tactic).enabled = true;
component.configService.setFeature('background_color', true);
configService.setFeature('background_color', true);
expect(component.getTechniqueBackground()).toEqual({ background: component.emulate_alpha('black') });
component.viewModel.highlightedTechniques.add('attack-pattern-0');
component.viewModel.selectTechnique(component.technique, component.tactic);
Expand All @@ -172,14 +164,14 @@ describe('ChangelogCellComponent', () => {
});

it('should get the underline color for the given technique', () => {
component.configService.setFeature('link_underline', true);
component.configService.link_color = 'purple';
configService.setFeature('link_underline', true);
configService.linkColor = 'purple';
expect(component.getTechniqueUnderlineColor()).toEqual('purple');
component.configService.setFeature('metadata_underline', true);
component.configService.metadata_color = 'blue';
configService.setFeature('metadata_underline', true);
configService.metadataColor = 'blue';
expect(component.getTechniqueUnderlineColor()).toEqual('blue');
component.configService.setFeature('comment_underline', true);
component.configService.comment_color = 'yellow';
configService.setFeature('comment_underline', true);
configService.commentColor = 'yellow';
expect(component.getTechniqueUnderlineColor()).toEqual('yellow');
});

Expand All @@ -192,7 +184,7 @@ describe('ChangelogCellComponent', () => {
component.isDarkTheme = false;
component.viewModel.layout._showAggregateScores = true;
expect(component.getTechniqueTextColor()).toEqual(tinycolor.mostReadable(component.emulate_alpha('black'), ['white', 'black']));
component.configService.setFeature('background_color', true);
configService.setFeature('background_color', true);
expect(component.getTechniqueTextColor()).toEqual(tinycolor.mostReadable(component.emulate_alpha('black'), ['white', 'black']));
component.viewModel.getTechniqueVM(component.technique, component.tactic).enabled = false;
expect(component.getTechniqueTextColor()).toEqual('#aaaaaa');
Expand Down
6 changes: 3 additions & 3 deletions nav-app/src/app/matrix/cell.ts
Original file line number Diff line number Diff line change
Expand Up @@ -144,13 +144,13 @@ export abstract class Cell {
if (this.tactic) {
let tvm = this.viewModel.getTechniqueVM(this.technique, this.tactic);
if (tvm.comment.length > 0 || this.hasNotes()) {
if (this.configService.getFeature('comment_underline')) return this.configService.comment_color;
if (this.configService.getFeature('comment_underline')) return this.configService.commentColor;
}
if (tvm.metadata.length > 0) {
if (this.configService.getFeature('metadata_underline')) return this.configService.metadata_color;
if (this.configService.getFeature('metadata_underline')) return this.configService.metadataColor;
}
if (tvm.links.length > 0) {
if (this.configService.getFeature('link_underline')) return this.configService.link_color;
if (this.configService.getFeature('link_underline')) return this.configService.linkColor;
}
}
return '';
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,12 +11,10 @@ describe('MatrixFlatComponent', () => {
imports: [HttpClientTestingModule],
declarations: [MatrixFlatComponent],
}).compileComponents();
}));

beforeEach(() => {
fixture = TestBed.createComponent(MatrixFlatComponent);
component = fixture.componentInstance;
});
}));

it('should create', () => {
expect(component).toBeTruthy();
Expand Down
102 changes: 11 additions & 91 deletions nav-app/src/app/matrix/technique-cell/technique-cell.component.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,67 +5,12 @@ import { TechniqueVM } from '../../classes';
import { Matrix, Tactic, Technique } from '../../classes/stix';
import { HttpClientTestingModule } from '@angular/common/http/testing';
import { Cell } from '../cell';
import * as MockData from '../../../tests/utils/mock-data';
import { ConfigService } from '../../services/config.service';

describe('TechniqueCellComponent', () => {
let component: TechniqueCellComponent;
let fixture: ComponentFixture<TechniqueCellComponent>;
let stixSDO = {
name: 'Name',
description: 'Description',
created: '2001-01-01T01:01:00.000Z',
modified: '2001-01-01T01:01:00.000Z',
x_mitre_version: '1.0',
};
let techniqueSDO = {
...stixSDO,
type: 'attack-pattern',
x_mitre_platforms: ['platform'],
kill_chain_phases: [
{
kill_chain_name: 'mitre-attack',
phase_name: 'tactic-name',
},
],
};
let t0000 = {
...techniqueSDO,
id: 'attack-pattern-0',
external_references: [{ external_id: 'T0000' }],
};
let t0000_000 = {
...techniqueSDO,
id: 'attack-pattern-1',
x_mitre_is_subtechnique: true,
external_references: [{ external_id: 'T0000.000' }],
};
let t0000_001 = {
...techniqueSDO,
id: 'attack-pattern-2',
x_mitre_is_subtechnique: true,
revoked: true,
external_references: [{ external_id: 'T0000.001' }],
};
let tacticSDO = {
...stixSDO,
id: 'tactic-0',
type: 'x-mitre-tactic',
x_mitre_shortname: 'tactic-name',
external_references: [{ external_id: 'TA0000' }],
};
let tacticSDO2 = {
...stixSDO,
id: 'tactic-1',
type: 'x-mitre-tactic',
x_mitre_shortname: 'tactic-name',
external_references: [{ external_id: 'TA0001' }],
};
let matrixSDO = {
...stixSDO,
id: 'matrix-0',
type: 'x-mitre-matrix',
tactic_refs: ['tactic-0'],
external_references: [{ external_id: 'enterprise-matrix' }],
};
let techniqueTacticUnionId = 'T0000^tactic-name';

beforeEach(() => {
Expand All @@ -74,29 +19,17 @@ describe('TechniqueCellComponent', () => {
providers: [ViewModelsService],
declarations: [TechniqueCellComponent],
});
let configService = TestBed.inject(ConfigService);
configService.versions = MockData.configData;
fixture = TestBed.createComponent(TechniqueCellComponent);
component = fixture.debugElement.componentInstance;
let versions = [
{
name: 'ATT&CK v13',
version: '13',
domains: [
{
name: 'Enterprise',
identifier: 'enterprise-attack',
data: ['https://raw.githubusercontent.com/mitre/cti/ATT%26CK-v13.1/enterprise-attack/enterprise-attack.json'],
},
],
},
];
component.dataService.setUpURLs(versions);
let sub1 = new Technique(t0000_000, [], null);
let sub2 = new Technique(t0000_001, [], null);
component.technique = new Technique(t0000, [sub1, sub2], null);
component.tactic = new Tactic(tacticSDO, [component.technique], null);
let sub1 = new Technique(MockData.T0000_000, [], null);
let sub2 = new Technique(MockData.T0000_001, [], null);
component.technique = new Technique(MockData.T0000, [sub1, sub2], null);
component.tactic = new Tactic(MockData.TA0000, [component.technique], null);
let map = new Map();
map.set(component.tactic.id, tacticSDO);
component.matrix = new Matrix(matrixSDO, map, [component.technique, sub1, sub2], null);
map.set(component.tactic.id, MockData.TA0000);
component.matrix = new Matrix(MockData.matrixSDO, map, [component.technique, sub1, sub2], null);
component.viewModel = component.viewModelsService.newViewModel('vm', 'enterprise-attack-13');
component.viewModel.setTechniqueVM(new TechniqueVM(techniqueTacticUnionId));
component.viewModel.setTechniqueVM(new TechniqueVM('T0000.000^tactic-name'));
Expand Down Expand Up @@ -158,7 +91,7 @@ describe('TechniqueCellComponent', () => {
const ttid = component.technique.get_technique_tactic_id(component.tactic);
component.viewModel.highlightedTechniques = new Set([ttid]);
component.viewModel.highlightedTechnique = component.technique;
component.viewModel.highlightedTactic = new Tactic(tacticSDO2, [component.technique], null);
component.viewModel.highlightedTactic = new Tactic(MockData.TA0001, [component.technique], null);
expect(component.showTooltip).toBe(false);
});

Expand Down Expand Up @@ -217,19 +150,6 @@ describe('TechniqueCellComponent', () => {
expect(unhighlightSpy).toHaveBeenCalled();
});

it('should return the number of annotated subtechniques', () => {
component.viewModel.getTechniqueVM = jasmine.createSpy('getTechniqueVM').and.callFake((subtechnique, tactic) => {
return {
...jasmine.createSpyObj('TechniqueVM', ['annotated', 'setIsVisible']),
annotated: jasmine.createSpy('annotated').and.returnValue(true),
};
});
const result = component.annotatedSubtechniques();
expect(component.viewModel.getTechniqueVM).toHaveBeenCalledTimes(2);
expect(component.viewModel.getTechniqueVM).toHaveBeenCalledWith(jasmine.any(Object), component.tactic);
expect(result).toEqual(component.applyControls([], component.tactic).length);
});

it('should return the correct class when not annotated and not editing', () => {
spyOn(Cell.prototype, 'getClass').and.returnValue('base-class');
spyOn(component, 'annotatedSubtechniques').and.returnValue(0);
Expand Down
Loading

0 comments on commit 19aa107

Please sign in to comment.