Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Refactor ConfigService #615

Merged
merged 14 commits into from
Feb 20, 2024
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