Compare commits

...

1 Commits

Author SHA1 Message Date
Marcel Haag 2568bc4fc5 feat: As an user I want to have the layout for my pentest 2022-09-01 17:27:12 +02:00
54 changed files with 718 additions and 184 deletions

View File

@ -70,12 +70,11 @@ export class PentestTableComponent implements OnInit {
.then( .then(
() => this.store.reset({ () => this.store.reset({
...this.store.snapshot(), ...this.store.snapshot(),
[PROJECT_STATE_NAME]: undefined // [PROJECT_STATE_NAME]: pentest
}) })
).finally(); ).finally();
*/ */
this.store.dispatch(new ChangePentest(pentest.id)); this.store.dispatch(new ChangePentest(pentest));
} }
// HTML only // HTML only

View File

@ -0,0 +1,25 @@
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { PentestCommentsComponent } from './pentest-comments.component';
describe('PentestCommentsComponent', () => {
let component: PentestCommentsComponent;
let fixture: ComponentFixture<PentestCommentsComponent>;
beforeEach(async () => {
await TestBed.configureTestingModule({
declarations: [ PentestCommentsComponent ]
})
.compileComponents();
});
beforeEach(() => {
fixture = TestBed.createComponent(PentestCommentsComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});

View File

@ -0,0 +1,15 @@
import { Component, OnInit } from '@angular/core';
@Component({
selector: 'app-pentest-comments',
templateUrl: './pentest-comments.component.html',
styleUrls: ['./pentest-comments.component.scss']
})
export class PentestCommentsComponent implements OnInit {
constructor() { }
ngOnInit(): void {
}
}

View File

@ -0,0 +1,27 @@
<div class="pentest-content">
<div class="content">
<nb-tabset>
<nb-tab tabTitle="{{ 'global.action.info' | translate }}">
<app-pentest-info></app-pentest-info>
</nb-tab>
<nb-tab tabTitle="{{ 'pentest.findings' | translate }} ({{currentNumberOfFindings$.getValue()}})">
<app-pentest-findings></app-pentest-findings>
</nb-tab>
<nb-tab tabTitle="{{ 'pentest.comments' | translate }} ({{currentNumberOfComments$.getValue()}})">
<app-pentest-comments></app-pentest-comments>
</nb-tab>
</nb-tabset>
</div>
<div fxLayoutAlign="end end" class="content-footer">
<button nbButton
class="save-pentest-button"
status="primary"
[disabled]="!pentestChanged$.getValue()"
title="{{ 'global.action.save' | translate }}"
(click)="onClickSavePentest()">
<span class="exit-element-text"> {{ 'global.action.save' | translate }} </span>
</button>
</div>
</div>

View File

@ -0,0 +1,18 @@
.pentest-content {
width: 100%;
height: 100%;
.content {
overflow: auto !important;
height: 95%;
// check fixed height
// background-color: #8f9bb3;
}
.content-footer {
height: 5%;
.save-pentest-button {
margin: 1rem 6rem 1rem 0;
}
}
}

View File

@ -0,0 +1,82 @@
import {ComponentFixture, TestBed} from '@angular/core/testing';
import {PentestContentComponent} from './pentest-content.component';
import {TranslateLoader, TranslateModule} from '@ngx-translate/core';
import {HttpLoaderFactory} from '../../../common-app.module';
import {HttpClient} from '@angular/common/http';
import {RouterTestingModule} from '@angular/router/testing';
import {NgxsModule, Store} from '@ngxs/store';
import {PROJECT_STATE_NAME, ProjectState, ProjectStateModel} from '@shared/stores/project-state/project-state';
import {BrowserAnimationsModule} from '@angular/platform-browser/animations';
import {HttpClientTestingModule} from '@angular/common/http/testing';
import {Category} from '@shared/models/category.model';
import {PentestStatus} from '@shared/models/pentest-status.model';
const DESIRED_PROJECT_STATE_SESSION: ProjectStateModel = {
selectedProject: {
id: '56c47c56-3bcd-45f1-a05b-c197dbd33111',
client: 'E Corp',
title: 'Some Mock API (v1.0) Scanning',
createdAt: new Date('2019-01-10T09:00:00'),
tester: 'Novatester',
testingProgress: 0,
createdBy: '11c47c56-3bcd-45f1-a05b-c197dbd33110'
},
// Manages Categories
disabledCategories: [],
selectedCategory: Category.INFORMATION_GATHERING,
// Manages Pentests of Category
disabledPentests: [],
selectedPentest: {
id: '56c47c56-3bcd-45f1-a05b-c197dbd33112',
category: Category.INFORMATION_GATHERING,
refNumber: 'OTF-001',
childEntries: [],
status: PentestStatus.NOT_STARTED,
findingsIds: [],
commentsIds: []
},
};
describe('PentestContentComponent', () => {
let component: PentestContentComponent;
let fixture: ComponentFixture<PentestContentComponent>;
let store: Store;
beforeEach(async () => {
await TestBed.configureTestingModule({
declarations: [
PentestContentComponent
],
imports: [
BrowserAnimationsModule,
HttpClientTestingModule,
TranslateModule.forRoot({
loader: {
provide: TranslateLoader,
useFactory: HttpLoaderFactory,
deps: [HttpClient]
}
}),
RouterTestingModule.withRoutes([]),
NgxsModule.forRoot([ProjectState])
]
})
.compileComponents();
});
beforeEach(() => {
fixture = TestBed.createComponent(PentestContentComponent);
store = TestBed.inject(Store);
store.reset({
...store.snapshot(),
[PROJECT_STATE_NAME]: DESIRED_PROJECT_STATE_SESSION
});
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});

View File

@ -0,0 +1,46 @@
import { Component, OnInit } from '@angular/core';
import * as FA from '@fortawesome/free-solid-svg-icons';
import {BehaviorSubject} from 'rxjs';
import {Store} from '@ngxs/store';
import {ProjectState} from '@shared/stores/project-state/project-state';
import {UntilDestroy, untilDestroyed} from '@ngneat/until-destroy';
import {Pentest} from '@shared/models/pentest.model';
@UntilDestroy()
@Component({
selector: 'app-pentest-content',
templateUrl: './pentest-content.component.html',
styleUrls: ['./pentest-content.component.scss']
})
export class PentestContentComponent implements OnInit {
readonly fa = FA;
pentest$: BehaviorSubject<Pentest> = new BehaviorSubject<Pentest>(null);
pentestChanged$: BehaviorSubject<boolean> = new BehaviorSubject<boolean>(false);
currentNumberOfFindings$: BehaviorSubject<number> = new BehaviorSubject<number>(0);
currentNumberOfComments$: BehaviorSubject<number> = new BehaviorSubject<number>(0);
constructor(private store: Store) { }
ngOnInit(): void {
this.store.select(ProjectState.pentest).pipe(
untilDestroyed(this)
).subscribe({
next: (selectedPentest: Pentest) => {
console.warn('Selected Pentest: ', selectedPentest);
this.pentest$.next(selectedPentest);
const findings = selectedPentest.findingsIds ? selectedPentest.findingsIds.length : 0;
this.currentNumberOfFindings$.next(findings);
const comments = selectedPentest.commentsIds ? selectedPentest.commentsIds.length : 0;
this.currentNumberOfComments$.next(comments);
},
error: err => {
console.error(err);
}
});
}
onClickSavePentest(): void {
console.info('to be implemented..');
}
}

View File

@ -0,0 +1,25 @@
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { PentestFindingsComponent } from './pentest-findings.component';
describe('PentestFindingsComponent', () => {
let component: PentestFindingsComponent;
let fixture: ComponentFixture<PentestFindingsComponent>;
beforeEach(async () => {
await TestBed.configureTestingModule({
declarations: [ PentestFindingsComponent ]
})
.compileComponents();
});
beforeEach(() => {
fixture = TestBed.createComponent(PentestFindingsComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});

View File

@ -0,0 +1,15 @@
import { Component, OnInit } from '@angular/core';
@Component({
selector: 'app-pentest-findings',
templateUrl: './pentest-findings.component.html',
styleUrls: ['./pentest-findings.component.scss']
})
export class PentestFindingsComponent implements OnInit {
constructor() { }
ngOnInit(): void {
}
}

View File

@ -0,0 +1,25 @@
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { PentestInfoComponent } from './pentest-info.component';
describe('PentestInfoComponent', () => {
let component: PentestInfoComponent;
let fixture: ComponentFixture<PentestInfoComponent>;
beforeEach(async () => {
await TestBed.configureTestingModule({
declarations: [ PentestInfoComponent ]
})
.compileComponents();
});
beforeEach(() => {
fixture = TestBed.createComponent(PentestInfoComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});

View File

@ -0,0 +1,15 @@
import { Component, OnInit } from '@angular/core';
@Component({
selector: 'app-pentest-info',
templateUrl: './pentest-info.component.html',
styleUrls: ['./pentest-info.component.scss']
})
export class PentestInfoComponent implements OnInit {
constructor() { }
ngOnInit(): void {
}
}

View File

@ -0,0 +1,20 @@
<div class="pentest-stepper" fxLayout="row" fxLayoutGap="2rem" fxLayoutAlign="space-between center">
<div class="exit-button-container">
<button nbButton
shape="round"
title="{{ 'global.action.exit' | translate }}"
(click)="onClickRouteBack()">
<fa-icon [icon]="fa.faLongArrowAltLeft"
class="exit-element-icon fa-lg">
</fa-icon>
<span class="exit-element-text"> {{ 'global.action.exit' | translate }} </span>
</button>
</div>
<h4>{{selectedProjectTitle$.getValue()}} / {{pentest$.getValue().refNumber}}</h4>
<div class="pentest-status-container">
<app-status-tag [currentStatus]="pentest$.getValue().status"></app-status-tag>
</div>
</div>

View File

@ -0,0 +1,17 @@
.pentest-stepper {
width: calc(100vw - 14%);
.exit-button-container {
.exit-element-icon {
}
.exit-element-text {
padding-left: 0.5rem;
}
}
.pentest-status-container {
display: flex;
align-content: flex-end;
margin-right: 0.5rem;
}
}

View File

@ -0,0 +1,80 @@
import {ComponentFixture, TestBed} from '@angular/core/testing';
import {PentestMenuComponent} from './pentest-menu.component';
import {BrowserAnimationsModule} from '@angular/platform-browser/animations';
import {HttpClientTestingModule} from '@angular/common/http/testing';
import {TranslateLoader, TranslateModule} from '@ngx-translate/core';
import {HttpLoaderFactory} from '../../../common-app.module';
import {HttpClient} from '@angular/common/http';
import {RouterTestingModule} from '@angular/router/testing';
import {NgxsModule, Store} from '@ngxs/store';
import {PROJECT_STATE_NAME, ProjectState, ProjectStateModel} from '@shared/stores/project-state/project-state';
import {Category} from '@shared/models/category.model';
import {PentestStatus} from '@shared/models/pentest-status.model';
const DESIRED_PROJECT_STATE_SESSION: ProjectStateModel = {
selectedProject: {
id: '56c47c56-3bcd-45f1-a05b-c197dbd33111',
client: 'E Corp',
title: 'Some Mock API (v1.0) Scanning',
createdAt: new Date('2019-01-10T09:00:00'),
tester: 'Novatester',
testingProgress: 0,
createdBy: '11c47c56-3bcd-45f1-a05b-c197dbd33110'
},
// Manages Categories
disabledCategories: [],
selectedCategory: Category.INFORMATION_GATHERING,
// Manages Pentests of Category
disabledPentests: [],
selectedPentest: {
id: '56c47c56-3bcd-45f1-a05b-c197dbd33112',
category: Category.INFORMATION_GATHERING,
refNumber: 'OTF-001',
childEntries: [],
status: PentestStatus.NOT_STARTED,
findingsIds: [],
commentsIds: []
},
};
describe('PentestMenuComponent', () => {
let component: PentestMenuComponent;
let fixture: ComponentFixture<PentestMenuComponent>;
let store: Store;
beforeEach(async () => {
await TestBed.configureTestingModule({
declarations: [PentestMenuComponent],
imports: [
BrowserAnimationsModule,
HttpClientTestingModule,
TranslateModule.forRoot({
loader: {
provide: TranslateLoader,
useFactory: HttpLoaderFactory,
deps: [HttpClient]
}
}),
RouterTestingModule.withRoutes([]),
NgxsModule.forRoot([ProjectState])
]
})
.compileComponents();
});
beforeEach(() => {
fixture = TestBed.createComponent(PentestMenuComponent);
store = TestBed.inject(Store);
store.reset({
...store.snapshot(),
[PROJECT_STATE_NAME]: DESIRED_PROJECT_STATE_SESSION
});
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});

View File

@ -0,0 +1,63 @@
import {Component, OnInit} from '@angular/core';
import * as FA from '@fortawesome/free-solid-svg-icons';
import {UntilDestroy, untilDestroyed} from '@ngneat/until-destroy';
import {Route} from '@shared/models/route.enum';
import {Store} from '@ngxs/store';
import {Router} from '@angular/router';
import {ChangePentest} from '@shared/stores/project-state/project-state.actions';
import {BehaviorSubject} from 'rxjs';
import {PentestStatus} from '@shared/models/pentest-status.model';
import {ProjectState} from '@shared/stores/project-state/project-state';
import {Project} from '@shared/models/project.model';
import {Pentest} from '@shared/models/pentest.model';
@UntilDestroy()
@Component({
selector: 'app-pentest-menu',
templateUrl: './pentest-menu.component.html',
styleUrls: ['./pentest-menu.component.scss']
})
export class PentestMenuComponent implements OnInit {
// HTML only
readonly fa = FA;
pentest$: BehaviorSubject<Pentest> = new BehaviorSubject<Pentest>(null);
selectedProjectTitle$: BehaviorSubject<string> = new BehaviorSubject<string>('');
constructor(private store: Store,
private readonly router: Router) {
}
ngOnInit(): void {
this.store.select(ProjectState.project).pipe(
untilDestroyed(this)
).subscribe({
next: (selectedProject: Project) => {
this.selectedProjectTitle$.next(selectedProject?.title);
},
error: err => {
console.error(err);
}
});
this.store.select(ProjectState.pentest).pipe(
untilDestroyed(this)
).subscribe({
next: (selectedPentest: Pentest) => {
this.pentest$.next(selectedPentest);
},
error: err => {
console.error(err);
}
});
}
onClickRouteBack(): void {
this.router.navigate([Route.PENTEST_OVERVIEW])
.then(
() => {
this.store.dispatch(new ChangePentest(null));
}
).finally();
}
}

View File

@ -1,5 +1,15 @@
<nb-layout> <div fxFlex class="pentest">
<nb-layout-header> <nb-layout fxFlex>
<p>pentest works!</p> <nb-layout-header fxFlex="0 1 max-content" class="stepper-column">
</nb-layout-header> <app-pentest-menu></app-pentest-menu>
</nb-layout> </nb-layout-header>
<nb-layout-column fxFlex="0 1 max-content" class="column-wrapper">
<nb-card class="content-column">
<nb-card-body>
<app-pentest-content></app-pentest-content>
</nb-card-body>
</nb-card>
</nb-layout-column>
</nb-layout>
</div>

View File

@ -0,0 +1,24 @@
@import '../../../assets/@theme/styles/themes';
@import '../../../assets/@theme/styles/_variables.scss';
.pentest {
width: 100vw;
height: calc(100vh - #{$header-height});
overflow: hidden;
.header-column {
width: 100vw;
height: $pentest-header-height;
}
.column-wrapper {
padding-left: 0 !important;
.content-column {
overflow: auto !important;
width: 100vw;
max-width: 100vw;
height: calc(100vh - #{$pentest-header-height} - #{$header-height});
}
}
}

View File

@ -2,11 +2,25 @@ import {NgModule} from '@angular/core';
import {CommonModule} from '@angular/common'; import {CommonModule} from '@angular/common';
import {RouterModule} from '@angular/router'; import {RouterModule} from '@angular/router';
import {PentestComponent} from './pentest.component'; import {PentestComponent} from './pentest.component';
import {NbLayoutModule} from '@nebular/theme'; import {NbButtonModule, NbCardModule, NbLayoutModule, NbTabsetModule} from '@nebular/theme';
import { PentestMenuComponent } from './pentest-menu/pentest-menu.component';
import { PentestContentComponent } from './pentest-content/pentest-content.component';
import {FlexLayoutModule} from '@angular/flex-layout';
import {FontAwesomeModule} from '@fortawesome/angular-fontawesome';
import {TranslateModule} from '@ngx-translate/core';
import {StatusTagModule} from '@shared/widgets/status-tag/status-tag.module';
import { PentestInfoComponent } from './pentest-content/pentest-info/pentest-info.component';
import { PentestFindingsComponent } from './pentest-content/pentest-findings/pentest-findings.component';
import { PentestCommentsComponent } from './pentest-content/pentest-comments/pentest-comments.component';
@NgModule({ @NgModule({
declarations: [ declarations: [
PentestComponent PentestComponent,
PentestMenuComponent,
PentestContentComponent,
PentestInfoComponent,
PentestFindingsComponent,
PentestCommentsComponent
], ],
imports: [ imports: [
CommonModule, CommonModule,
@ -14,7 +28,14 @@ import {NbLayoutModule} from '@nebular/theme';
path: '', path: '',
component: PentestComponent component: PentestComponent
}]), }]),
NbLayoutModule NbLayoutModule,
NbCardModule,
FlexLayoutModule,
FontAwesomeModule,
TranslateModule,
NbButtonModule,
StatusTagModule,
NbTabsetModule
] ]
}) })
export class PentestModule { export class PentestModule {

View File

@ -8,13 +8,14 @@
.header-column { .header-column {
width: 100vw; width: 100vw;
height: $pentest-header-height;
} }
.column-wrapper { .column-wrapper {
padding-left: 0 !important; padding-left: 0 !important;
.categories-column { .categories-column {
height: calc(100vh - #{$pentest-header-height}); height: calc(100vh - #{$pentest-header-height} - #{$header-height});
} }
} }
@ -23,7 +24,7 @@
.table-column { .table-column {
overflow: auto !important; overflow: auto !important;
height: calc(100vh - #{$pentest-header-height}); height: calc(100vh - #{$pentest-header-height} - #{$header-height});
} }
} }
} }

View File

@ -2,10 +2,12 @@
"global": { "global": {
"action.login": "Einloggen", "action.login": "Einloggen",
"action.retry": "Erneut Versuchen", "action.retry": "Erneut Versuchen",
"action.info": "Info",
"action.save": "Speichern", "action.save": "Speichern",
"action.confirm": "Bestätigen", "action.confirm": "Bestätigen",
"action.cancel": "Abbrechen", "action.cancel": "Abbrechen",
"action.return": "Zurück", "action.return": "Zurück",
"action.exit": "Beenden",
"action.update": "Speichern", "action.update": "Speichern",
"action.export": "Exportieren", "action.export": "Exportieren",
"action.yes": "Ja", "action.yes": "Ja",
@ -83,10 +85,8 @@
"not_started": "Nicht angefangen", "not_started": "Nicht angefangen",
"disabled": "Deaktiviert", "disabled": "Deaktiviert",
"open": "Offen", "open": "Offen",
"checked": "Geprüft", "in_progress": "In Bearbeitung",
"reported": "Gemeldet", "completed": "Fertig"
"under_review": "Unter Beurteilung",
"triaged": "Triagiert"
}, },
"info": { "info": {
"001": "Nutze Suchmaschinenerkennung und -aufklärung für Informationslecks", "001": "Nutze Suchmaschinenerkennung und -aufklärung für Informationslecks",

View File

@ -2,10 +2,12 @@
"global": { "global": {
"action.login": "Login", "action.login": "Login",
"action.retry": "Try again", "action.retry": "Try again",
"action.info": "Info",
"action.confirm": "Confirm", "action.confirm": "Confirm",
"action.save": "Save", "action.save": "Save",
"action.cancel": "Cancel", "action.cancel": "Cancel",
"action.return": "Return", "action.return": "Return",
"action.exit": "Exit",
"action.update": "Update", "action.update": "Update",
"action.export": "Export", "action.export": "Export",
"action.yes": "Yes", "action.yes": "Yes",
@ -83,10 +85,8 @@
"not_started": "Not Started", "not_started": "Not Started",
"disabled": "Disabled", "disabled": "Disabled",
"open": "Open", "open": "Open",
"checked": "Checked", "in_progress": "In progress",
"reported": "Reported", "completed": "Completed"
"under_review": "Under Review",
"triaged": "Triaged"
}, },
"info": { "info": {
"001": "Conduct Search Engine Discovery and Reconnaissance for Information Leakage", "001": "Conduct Search Engine Discovery and Reconnaissance for Information Leakage",

View File

@ -1,58 +1,58 @@
import {Pentest} from '@shared/models/pentest.model'; import {Pentest} from '@shared/models/pentest.model';
import {Category} from '@shared/models/category.model'; import {Category} from '@shared/models/category.model';
import {Status} from '@shared/models/status.model'; import {PentestStatus} from '@shared/models/pentest-status.model';
export function getAUTHN_Pentests(): Pentest[] { export function getAUTHN_Pentests(): Pentest[] {
return [ return [
{ {
category: Category.AUTHENTICATION_TESTING, category: Category.AUTHENTICATION_TESTING,
refNumber: 'OTG-AUTHN-001', refNumber: 'OTG-AUTHN-001',
status: Status.NOT_STARTED status: PentestStatus.NOT_STARTED
}, },
{ {
category: Category.AUTHENTICATION_TESTING, category: Category.AUTHENTICATION_TESTING,
refNumber: 'OTG-AUTHN-002', refNumber: 'OTG-AUTHN-002',
status: Status.NOT_STARTED status: PentestStatus.NOT_STARTED
}, },
{ {
category: Category.AUTHENTICATION_TESTING, category: Category.AUTHENTICATION_TESTING,
refNumber: 'OTG-AUTHN-003', refNumber: 'OTG-AUTHN-003',
status: Status.NOT_STARTED status: PentestStatus.NOT_STARTED
}, },
{ {
category: Category.AUTHENTICATION_TESTING, category: Category.AUTHENTICATION_TESTING,
refNumber: 'OTG-AUTHN-004', refNumber: 'OTG-AUTHN-004',
status: Status.NOT_STARTED status: PentestStatus.NOT_STARTED
}, },
{ {
category: Category.AUTHENTICATION_TESTING, category: Category.AUTHENTICATION_TESTING,
refNumber: 'OTG-AUTHN-005', refNumber: 'OTG-AUTHN-005',
status: Status.NOT_STARTED status: PentestStatus.NOT_STARTED
}, },
{ {
category: Category.AUTHENTICATION_TESTING, category: Category.AUTHENTICATION_TESTING,
refNumber: 'OTG-AUTHN-006', refNumber: 'OTG-AUTHN-006',
status: Status.NOT_STARTED status: PentestStatus.NOT_STARTED
}, },
{ {
category: Category.AUTHENTICATION_TESTING, category: Category.AUTHENTICATION_TESTING,
refNumber: 'OTG-AUTHN-007', refNumber: 'OTG-AUTHN-007',
status: Status.NOT_STARTED status: PentestStatus.NOT_STARTED
}, },
{ {
category: Category.AUTHENTICATION_TESTING, category: Category.AUTHENTICATION_TESTING,
refNumber: 'OTG-AUTHN-008', refNumber: 'OTG-AUTHN-008',
status: Status.NOT_STARTED status: PentestStatus.NOT_STARTED
}, },
{ {
category: Category.AUTHENTICATION_TESTING, category: Category.AUTHENTICATION_TESTING,
refNumber: 'OTG-AUTHN-009', refNumber: 'OTG-AUTHN-009',
status: Status.NOT_STARTED status: PentestStatus.NOT_STARTED
}, },
{ {
category: Category.AUTHENTICATION_TESTING, category: Category.AUTHENTICATION_TESTING,
refNumber: 'OTG-AUTHN-010', refNumber: 'OTG-AUTHN-010',
status: Status.NOT_STARTED status: PentestStatus.NOT_STARTED
} }
]; ];
} }

View File

@ -1,28 +1,28 @@
import {Pentest} from '@shared/models/pentest.model'; import {Pentest} from '@shared/models/pentest.model';
import {Category} from '@shared/models/category.model'; import {Category} from '@shared/models/category.model';
import {Status} from '@shared/models/status.model'; import {PentestStatus} from '@shared/models/pentest-status.model';
export function getAUTHZ_Pentests(): Pentest[] { export function getAUTHZ_Pentests(): Pentest[] {
return [ return [
{ {
category: Category.AUTHORIZATION_TESTING, category: Category.AUTHORIZATION_TESTING,
refNumber: 'OTG-AUTHZ-001', refNumber: 'OTG-AUTHZ-001',
status: Status.NOT_STARTED status: PentestStatus.NOT_STARTED
}, },
{ {
category: Category.AUTHORIZATION_TESTING, category: Category.AUTHORIZATION_TESTING,
refNumber: 'OTG-AUTHZ-002', refNumber: 'OTG-AUTHZ-002',
status: Status.NOT_STARTED status: PentestStatus.NOT_STARTED
}, },
{ {
category: Category.AUTHORIZATION_TESTING, category: Category.AUTHORIZATION_TESTING,
refNumber: 'OTG-AUTHZ-003', refNumber: 'OTG-AUTHZ-003',
status: Status.NOT_STARTED status: PentestStatus.NOT_STARTED
}, },
{ {
category: Category.AUTHORIZATION_TESTING, category: Category.AUTHORIZATION_TESTING,
refNumber: 'OTG-AUTHZ-004', refNumber: 'OTG-AUTHZ-004',
status: Status.NOT_STARTED status: PentestStatus.NOT_STARTED
} }
]; ];
} }

View File

@ -1,53 +1,53 @@
import {Pentest} from '@shared/models/pentest.model'; import {Pentest} from '@shared/models/pentest.model';
import {Category} from '@shared/models/category.model'; import {Category} from '@shared/models/category.model';
import {Status} from '@shared/models/status.model'; import {PentestStatus} from '@shared/models/pentest-status.model';
export function getBUSLOGIC_Pentests(): Pentest[] { export function getBUSLOGIC_Pentests(): Pentest[] {
return [ return [
{ {
category: Category.BUSINESS_LOGIC_TESTING, category: Category.BUSINESS_LOGIC_TESTING,
refNumber: 'OTG-BUSLOGIC-001', refNumber: 'OTG-BUSLOGIC-001',
status: Status.NOT_STARTED status: PentestStatus.NOT_STARTED
}, },
{ {
category: Category.BUSINESS_LOGIC_TESTING, category: Category.BUSINESS_LOGIC_TESTING,
refNumber: 'OTG-BUSLOGIC-002', refNumber: 'OTG-BUSLOGIC-002',
status: Status.NOT_STARTED status: PentestStatus.NOT_STARTED
}, },
{ {
category: Category.BUSINESS_LOGIC_TESTING, category: Category.BUSINESS_LOGIC_TESTING,
refNumber: 'OTG-BUSLOGIC-003', refNumber: 'OTG-BUSLOGIC-003',
status: Status.NOT_STARTED status: PentestStatus.NOT_STARTED
}, },
{ {
category: Category.BUSINESS_LOGIC_TESTING, category: Category.BUSINESS_LOGIC_TESTING,
refNumber: 'OTG-BUSLOGIC-004', refNumber: 'OTG-BUSLOGIC-004',
status: Status.NOT_STARTED status: PentestStatus.NOT_STARTED
}, },
{ {
category: Category.BUSINESS_LOGIC_TESTING, category: Category.BUSINESS_LOGIC_TESTING,
refNumber: 'OTG-BUSLOGIC-005', refNumber: 'OTG-BUSLOGIC-005',
status: Status.NOT_STARTED status: PentestStatus.NOT_STARTED
}, },
{ {
category: Category.BUSINESS_LOGIC_TESTING, category: Category.BUSINESS_LOGIC_TESTING,
refNumber: 'OTG-BUSLOGIC-006', refNumber: 'OTG-BUSLOGIC-006',
status: Status.NOT_STARTED status: PentestStatus.NOT_STARTED
}, },
{ {
category: Category.BUSINESS_LOGIC_TESTING, category: Category.BUSINESS_LOGIC_TESTING,
refNumber: 'OTG-BUSLOGIC-007', refNumber: 'OTG-BUSLOGIC-007',
status: Status.NOT_STARTED status: PentestStatus.NOT_STARTED
}, },
{ {
category: Category.BUSINESS_LOGIC_TESTING, category: Category.BUSINESS_LOGIC_TESTING,
refNumber: 'OTG-BUSLOGIC-008', refNumber: 'OTG-BUSLOGIC-008',
status: Status.NOT_STARTED status: PentestStatus.NOT_STARTED
}, },
{ {
category: Category.BUSINESS_LOGIC_TESTING, category: Category.BUSINESS_LOGIC_TESTING,
refNumber: 'OTG-BUSLOGIC-009', refNumber: 'OTG-BUSLOGIC-009',
status: Status.NOT_STARTED status: PentestStatus.NOT_STARTED
} }
]; ];
} }

View File

@ -1,68 +1,68 @@
import {Pentest} from '@shared/models/pentest.model'; import {Pentest} from '@shared/models/pentest.model';
import {Category} from '@shared/models/category.model'; import {Category} from '@shared/models/category.model';
import {Status} from '@shared/models/status.model'; import {PentestStatus} from '@shared/models/pentest-status.model';
export function getCLIENT_Pentests(): Pentest[] { export function getCLIENT_Pentests(): Pentest[] {
return [ return [
{ {
category: Category.CLIENT_SIDE_TESTING, category: Category.CLIENT_SIDE_TESTING,
refNumber: 'OTG-CLIENT-001', refNumber: 'OTG-CLIENT-001',
status: Status.NOT_STARTED status: PentestStatus.NOT_STARTED
}, },
{ {
category: Category.CLIENT_SIDE_TESTING, category: Category.CLIENT_SIDE_TESTING,
refNumber: 'OTG-CLIENT-002', refNumber: 'OTG-CLIENT-002',
status: Status.NOT_STARTED status: PentestStatus.NOT_STARTED
}, },
{ {
category: Category.CLIENT_SIDE_TESTING, category: Category.CLIENT_SIDE_TESTING,
refNumber: 'OTG-CLIENT-003', refNumber: 'OTG-CLIENT-003',
status: Status.NOT_STARTED status: PentestStatus.NOT_STARTED
}, },
{ {
category: Category.CLIENT_SIDE_TESTING, category: Category.CLIENT_SIDE_TESTING,
refNumber: 'OTG-CLIENT-004', refNumber: 'OTG-CLIENT-004',
status: Status.NOT_STARTED status: PentestStatus.NOT_STARTED
}, },
{ {
category: Category.CLIENT_SIDE_TESTING, category: Category.CLIENT_SIDE_TESTING,
refNumber: 'OTG-CLIENT-005', refNumber: 'OTG-CLIENT-005',
status: Status.NOT_STARTED status: PentestStatus.NOT_STARTED
}, },
{ {
category: Category.CLIENT_SIDE_TESTING, category: Category.CLIENT_SIDE_TESTING,
refNumber: 'OTG-CLIENT-006', refNumber: 'OTG-CLIENT-006',
status: Status.NOT_STARTED status: PentestStatus.NOT_STARTED
}, },
{ {
category: Category.CLIENT_SIDE_TESTING, category: Category.CLIENT_SIDE_TESTING,
refNumber: 'OTG-CLIENT-007', refNumber: 'OTG-CLIENT-007',
status: Status.NOT_STARTED status: PentestStatus.NOT_STARTED
}, },
{ {
category: Category.CLIENT_SIDE_TESTING, category: Category.CLIENT_SIDE_TESTING,
refNumber: 'OTG-CLIENT-008', refNumber: 'OTG-CLIENT-008',
status: Status.NOT_STARTED status: PentestStatus.NOT_STARTED
}, },
{ {
category: Category.CLIENT_SIDE_TESTING, category: Category.CLIENT_SIDE_TESTING,
refNumber: 'OTG-CLIENT-009', refNumber: 'OTG-CLIENT-009',
status: Status.NOT_STARTED status: PentestStatus.NOT_STARTED
}, },
{ {
category: Category.CLIENT_SIDE_TESTING, category: Category.CLIENT_SIDE_TESTING,
refNumber: 'OTG-CLIENT-010', refNumber: 'OTG-CLIENT-010',
status: Status.NOT_STARTED status: PentestStatus.NOT_STARTED
}, },
{ {
category: Category.CLIENT_SIDE_TESTING, category: Category.CLIENT_SIDE_TESTING,
refNumber: 'OTG-CLIENT-011', refNumber: 'OTG-CLIENT-011',
status: Status.NOT_STARTED status: PentestStatus.NOT_STARTED
}, },
{ {
category: Category.CLIENT_SIDE_TESTING, category: Category.CLIENT_SIDE_TESTING,
refNumber: 'OTG-CLIENT-012', refNumber: 'OTG-CLIENT-012',
status: Status.NOT_STARTED status: PentestStatus.NOT_STARTED
} }
]; ];
} }

View File

@ -1,48 +1,48 @@
import {Pentest} from '@shared/models/pentest.model'; import {Pentest} from '@shared/models/pentest.model';
import {Category} from '@shared/models/category.model'; import {Category} from '@shared/models/category.model';
import {Status} from '@shared/models/status.model'; import {PentestStatus} from '@shared/models/pentest-status.model';
export function getCONFIG_Pentests(): Pentest[] { export function getCONFIG_Pentests(): Pentest[] {
return [ return [
{ {
category: Category.CONFIGURATION_AND_DEPLOY_MANAGEMENT_TESTING, category: Category.CONFIGURATION_AND_DEPLOY_MANAGEMENT_TESTING,
refNumber: 'OTG-CONFIG-001', refNumber: 'OTG-CONFIG-001',
status: Status.NOT_STARTED status: PentestStatus.NOT_STARTED
}, },
{ {
category: Category.CONFIGURATION_AND_DEPLOY_MANAGEMENT_TESTING, category: Category.CONFIGURATION_AND_DEPLOY_MANAGEMENT_TESTING,
refNumber: 'OTG-CONFIG-002', refNumber: 'OTG-CONFIG-002',
status: Status.NOT_STARTED status: PentestStatus.NOT_STARTED
}, },
{ {
category: Category.CONFIGURATION_AND_DEPLOY_MANAGEMENT_TESTING, category: Category.CONFIGURATION_AND_DEPLOY_MANAGEMENT_TESTING,
refNumber: 'OTG-CONFIG-003', refNumber: 'OTG-CONFIG-003',
status: Status.NOT_STARTED status: PentestStatus.NOT_STARTED
}, },
{ {
category: Category.CONFIGURATION_AND_DEPLOY_MANAGEMENT_TESTING, category: Category.CONFIGURATION_AND_DEPLOY_MANAGEMENT_TESTING,
refNumber: 'OTG-CONFIG-004', refNumber: 'OTG-CONFIG-004',
status: Status.NOT_STARTED status: PentestStatus.NOT_STARTED
}, },
{ {
category: Category.CONFIGURATION_AND_DEPLOY_MANAGEMENT_TESTING, category: Category.CONFIGURATION_AND_DEPLOY_MANAGEMENT_TESTING,
refNumber: 'OTG-CONFIG-005', refNumber: 'OTG-CONFIG-005',
status: Status.NOT_STARTED status: PentestStatus.NOT_STARTED
}, },
{ {
category: Category.CONFIGURATION_AND_DEPLOY_MANAGEMENT_TESTING, category: Category.CONFIGURATION_AND_DEPLOY_MANAGEMENT_TESTING,
refNumber: 'OTG-CONFIG-006', refNumber: 'OTG-CONFIG-006',
status: Status.NOT_STARTED status: PentestStatus.NOT_STARTED
}, },
{ {
category: Category.CONFIGURATION_AND_DEPLOY_MANAGEMENT_TESTING, category: Category.CONFIGURATION_AND_DEPLOY_MANAGEMENT_TESTING,
refNumber: 'OTG-CONFIG-007', refNumber: 'OTG-CONFIG-007',
status: Status.NOT_STARTED status: PentestStatus.NOT_STARTED
}, },
{ {
category: Category.CONFIGURATION_AND_DEPLOY_MANAGEMENT_TESTING, category: Category.CONFIGURATION_AND_DEPLOY_MANAGEMENT_TESTING,
refNumber: 'OTG-CONFIG-008', refNumber: 'OTG-CONFIG-008',
status: Status.NOT_STARTED status: PentestStatus.NOT_STARTED
} }
]; ];
} }

View File

@ -1,23 +1,23 @@
import {Pentest} from '@shared/models/pentest.model'; import {Pentest} from '@shared/models/pentest.model';
import {Category} from '@shared/models/category.model'; import {Category} from '@shared/models/category.model';
import {Status} from '@shared/models/status.model'; import {PentestStatus} from '@shared/models/pentest-status.model';
export function getCRYPST_Pentests(): Pentest[] { export function getCRYPST_Pentests(): Pentest[] {
return [ return [
{ {
category: Category.CRYPTOGRAPHY, category: Category.CRYPTOGRAPHY,
refNumber: 'OTG-CRYPST-001', refNumber: 'OTG-CRYPST-001',
status: Status.NOT_STARTED status: PentestStatus.NOT_STARTED
}, },
{ {
category: Category.CRYPTOGRAPHY, category: Category.CRYPTOGRAPHY,
refNumber: 'OTG-CRYPST-002', refNumber: 'OTG-CRYPST-002',
status: Status.NOT_STARTED status: PentestStatus.NOT_STARTED
}, },
{ {
category: Category.CRYPTOGRAPHY, category: Category.CRYPTOGRAPHY,
refNumber: 'OTG-CRYPST-003', refNumber: 'OTG-CRYPST-003',
status: Status.NOT_STARTED status: PentestStatus.NOT_STARTED
} }
]; ];
} }

View File

@ -1,18 +1,18 @@
import {Pentest} from '@shared/models/pentest.model'; import {Pentest} from '@shared/models/pentest.model';
import {Category} from '@shared/models/category.model'; import {Category} from '@shared/models/category.model';
import {Status} from '@shared/models/status.model'; import {PentestStatus} from '@shared/models/pentest-status.model';
export function getERR_Pentests(): Pentest[] { export function getERR_Pentests(): Pentest[] {
return [ return [
{ {
category: Category.ERROR_HANDLING, category: Category.ERROR_HANDLING,
refNumber: 'OTG-ERR-001', refNumber: 'OTG-ERR-001',
status: Status.NOT_STARTED status: PentestStatus.NOT_STARTED
}, },
{ {
category: Category.ERROR_HANDLING, category: Category.ERROR_HANDLING,
refNumber: 'OTG-ERR-002', refNumber: 'OTG-ERR-002',
status: Status.NOT_STARTED status: PentestStatus.NOT_STARTED
} }
]; ];
} }

View File

@ -1,43 +1,43 @@
import {Pentest} from '@shared/models/pentest.model'; import {Pentest} from '@shared/models/pentest.model';
import {Category} from '@shared/models/category.model'; import {Category} from '@shared/models/category.model';
import {Status} from '@shared/models/status.model'; import {PentestStatus} from '@shared/models/pentest-status.model';
export function getIDENT_Pentests(): Pentest[] { export function getIDENT_Pentests(): Pentest[] {
return [ return [
{ {
category: Category.IDENTITY_MANAGEMENT_TESTING, category: Category.IDENTITY_MANAGEMENT_TESTING,
refNumber: 'OTG-IDENT-001', refNumber: 'OTG-IDENT-001',
status: Status.NOT_STARTED status: PentestStatus.NOT_STARTED
}, },
{ {
category: Category.IDENTITY_MANAGEMENT_TESTING, category: Category.IDENTITY_MANAGEMENT_TESTING,
refNumber: 'OTG-IDENT-002', refNumber: 'OTG-IDENT-002',
status: Status.NOT_STARTED status: PentestStatus.NOT_STARTED
}, },
{ {
category: Category.IDENTITY_MANAGEMENT_TESTING, category: Category.IDENTITY_MANAGEMENT_TESTING,
refNumber: 'OTG-IDENT-003', refNumber: 'OTG-IDENT-003',
status: Status.NOT_STARTED status: PentestStatus.NOT_STARTED
}, },
{ {
category: Category.IDENTITY_MANAGEMENT_TESTING, category: Category.IDENTITY_MANAGEMENT_TESTING,
refNumber: 'OTG-IDENT-004', refNumber: 'OTG-IDENT-004',
status: Status.NOT_STARTED status: PentestStatus.NOT_STARTED
}, },
{ {
category: Category.IDENTITY_MANAGEMENT_TESTING, category: Category.IDENTITY_MANAGEMENT_TESTING,
refNumber: 'OTG-IDENT-005', refNumber: 'OTG-IDENT-005',
status: Status.NOT_STARTED status: PentestStatus.NOT_STARTED
}, },
{ {
category: Category.IDENTITY_MANAGEMENT_TESTING, category: Category.IDENTITY_MANAGEMENT_TESTING,
refNumber: 'OTG-IDENT-006', refNumber: 'OTG-IDENT-006',
status: Status.NOT_STARTED status: PentestStatus.NOT_STARTED
}, },
{ {
category: Category.IDENTITY_MANAGEMENT_TESTING, category: Category.IDENTITY_MANAGEMENT_TESTING,
refNumber: 'OTG-IDENT-007', refNumber: 'OTG-IDENT-007',
status: Status.NOT_STARTED status: PentestStatus.NOT_STARTED
} }
]; ];
} }

View File

@ -1,5 +1,5 @@
import {Pentest} from '@shared/models/pentest.model'; import {Pentest} from '@shared/models/pentest.model';
import {Status} from '@shared/models/status.model'; import {PentestStatus} from '@shared/models/pentest-status.model';
import {Category} from '@shared/models/category.model'; import {Category} from '@shared/models/category.model';
export function getINFO_Pentests(): Pentest[] { export function getINFO_Pentests(): Pentest[] {
@ -7,52 +7,52 @@ export function getINFO_Pentests(): Pentest[] {
{ {
category: Category.INFORMATION_GATHERING, category: Category.INFORMATION_GATHERING,
refNumber: 'OTG-INFO-001', refNumber: 'OTG-INFO-001',
status: Status.NOT_STARTED status: PentestStatus.NOT_STARTED
}, },
{ {
category: Category.INFORMATION_GATHERING, category: Category.INFORMATION_GATHERING,
refNumber: 'OTG-INFO-002', refNumber: 'OTG-INFO-002',
status: Status.NOT_STARTED status: PentestStatus.NOT_STARTED
}, },
{ {
category: Category.INFORMATION_GATHERING, category: Category.INFORMATION_GATHERING,
refNumber: 'OTG-INFO-003', refNumber: 'OTG-INFO-003',
status: Status.NOT_STARTED status: PentestStatus.NOT_STARTED
}, },
{ {
category: Category.INFORMATION_GATHERING, category: Category.INFORMATION_GATHERING,
refNumber: 'OTG-INFO-004', refNumber: 'OTG-INFO-004',
status: Status.NOT_STARTED, status: PentestStatus.NOT_STARTED,
}, },
{ {
category: Category.INFORMATION_GATHERING, category: Category.INFORMATION_GATHERING,
refNumber: 'OTG-INFO-005', refNumber: 'OTG-INFO-005',
status: Status.NOT_STARTED, status: PentestStatus.NOT_STARTED,
}, },
{ {
category: Category.INFORMATION_GATHERING, category: Category.INFORMATION_GATHERING,
refNumber: 'OTG-INFO-006', refNumber: 'OTG-INFO-006',
status: Status.NOT_STARTED, status: PentestStatus.NOT_STARTED,
}, },
{ {
category: Category.INFORMATION_GATHERING, category: Category.INFORMATION_GATHERING,
refNumber: 'OTG-INFO-007', refNumber: 'OTG-INFO-007',
status: Status.NOT_STARTED, status: PentestStatus.NOT_STARTED,
}, },
{ {
category: Category.INFORMATION_GATHERING, category: Category.INFORMATION_GATHERING,
refNumber: 'OTG-INFO-008', refNumber: 'OTG-INFO-008',
status: Status.NOT_STARTED, status: PentestStatus.NOT_STARTED,
}, },
{ {
category: Category.INFORMATION_GATHERING, category: Category.INFORMATION_GATHERING,
refNumber: 'OTG-INFO-009', refNumber: 'OTG-INFO-009',
status: Status.NOT_STARTED, status: PentestStatus.NOT_STARTED,
}, },
{ {
category: Category.INFORMATION_GATHERING, category: Category.INFORMATION_GATHERING,
refNumber: 'OTG-INFO-010', refNumber: 'OTG-INFO-010',
status: Status.NOT_STARTED, status: PentestStatus.NOT_STARTED,
} }
]; ];
} }

View File

@ -1,149 +1,149 @@
import {Pentest} from '@shared/models/pentest.model'; import {Pentest} from '@shared/models/pentest.model';
import {Category} from '@shared/models/category.model'; import {Category} from '@shared/models/category.model';
import {Status} from '@shared/models/status.model'; import {PentestStatus} from '@shared/models/pentest-status.model';
export function getINPVAL_Pentests(): Pentest[] { export function getINPVAL_Pentests(): Pentest[] {
return [ return [
{ {
category: Category.INPUT_VALIDATION_TESTING, category: Category.INPUT_VALIDATION_TESTING,
refNumber: 'OTG-INPVAL-001', refNumber: 'OTG-INPVAL-001',
status: Status.NOT_STARTED status: PentestStatus.NOT_STARTED
}, },
{ {
category: Category.INPUT_VALIDATION_TESTING, category: Category.INPUT_VALIDATION_TESTING,
refNumber: 'OTG-INPVAL-002', refNumber: 'OTG-INPVAL-002',
status: Status.NOT_STARTED status: PentestStatus.NOT_STARTED
}, },
{ {
category: Category.INPUT_VALIDATION_TESTING, category: Category.INPUT_VALIDATION_TESTING,
refNumber: 'OTG-INPVAL-003', refNumber: 'OTG-INPVAL-003',
status: Status.NOT_STARTED status: PentestStatus.NOT_STARTED
}, },
{ {
category: Category.INPUT_VALIDATION_TESTING, category: Category.INPUT_VALIDATION_TESTING,
refNumber: 'OTG-INPVAL-004', refNumber: 'OTG-INPVAL-004',
status: Status.NOT_STARTED status: PentestStatus.NOT_STARTED
}, },
{ {
category: Category.INPUT_VALIDATION_TESTING, category: Category.INPUT_VALIDATION_TESTING,
refNumber: 'OTG-INPVAL-005', refNumber: 'OTG-INPVAL-005',
status: Status.NOT_STARTED status: PentestStatus.NOT_STARTED
}, },
{ {
category: Category.INPUT_VALIDATION_TESTING, category: Category.INPUT_VALIDATION_TESTING,
refNumber: 'OTG-INPVAL-006', refNumber: 'OTG-INPVAL-006',
status: Status.NOT_STARTED, status: PentestStatus.NOT_STARTED,
childEntries: [ childEntries: [
{ {
category: Category.INPUT_VALIDATION_TESTING, category: Category.INPUT_VALIDATION_TESTING,
refNumber: 'OTG-INPVAL-006_1', refNumber: 'OTG-INPVAL-006_1',
status: Status.NOT_STARTED status: PentestStatus.NOT_STARTED
}, },
{ {
category: Category.INPUT_VALIDATION_TESTING, category: Category.INPUT_VALIDATION_TESTING,
refNumber: 'OTG-INPVAL-006_2', refNumber: 'OTG-INPVAL-006_2',
status: Status.NOT_STARTED status: PentestStatus.NOT_STARTED
}, },
{ {
category: Category.INPUT_VALIDATION_TESTING, category: Category.INPUT_VALIDATION_TESTING,
refNumber: 'OTG-INPVAL-006_3', refNumber: 'OTG-INPVAL-006_3',
status: Status.NOT_STARTED status: PentestStatus.NOT_STARTED
}, },
{ {
category: Category.INPUT_VALIDATION_TESTING, category: Category.INPUT_VALIDATION_TESTING,
refNumber: 'OTG-INPVAL-006_4', refNumber: 'OTG-INPVAL-006_4',
status: Status.NOT_STARTED status: PentestStatus.NOT_STARTED
}, },
{ {
category: Category.INPUT_VALIDATION_TESTING, category: Category.INPUT_VALIDATION_TESTING,
refNumber: 'OTG-INPVAL-006_5', refNumber: 'OTG-INPVAL-006_5',
status: Status.NOT_STARTED status: PentestStatus.NOT_STARTED
}, },
] ]
}, },
{ {
category: Category.INPUT_VALIDATION_TESTING, category: Category.INPUT_VALIDATION_TESTING,
refNumber: 'OTG-INPVAL-007', refNumber: 'OTG-INPVAL-007',
status: Status.NOT_STARTED status: PentestStatus.NOT_STARTED
}, },
{ {
category: Category.INPUT_VALIDATION_TESTING, category: Category.INPUT_VALIDATION_TESTING,
refNumber: 'OTG-INPVAL-008', refNumber: 'OTG-INPVAL-008',
status: Status.NOT_STARTED status: PentestStatus.NOT_STARTED
}, },
{ {
category: Category.INPUT_VALIDATION_TESTING, category: Category.INPUT_VALIDATION_TESTING,
refNumber: 'OTG-INPVAL-009', refNumber: 'OTG-INPVAL-009',
status: Status.NOT_STARTED status: PentestStatus.NOT_STARTED
}, },
{ {
category: Category.INPUT_VALIDATION_TESTING, category: Category.INPUT_VALIDATION_TESTING,
refNumber: 'OTG-INPVAL-010', refNumber: 'OTG-INPVAL-010',
status: Status.NOT_STARTED status: PentestStatus.NOT_STARTED
}, },
{ {
category: Category.INPUT_VALIDATION_TESTING, category: Category.INPUT_VALIDATION_TESTING,
refNumber: 'OTG-INPVAL-011', refNumber: 'OTG-INPVAL-011',
status: Status.NOT_STARTED status: PentestStatus.NOT_STARTED
}, },
{ {
category: Category.INPUT_VALIDATION_TESTING, category: Category.INPUT_VALIDATION_TESTING,
refNumber: 'OTG-INPVAL-012', refNumber: 'OTG-INPVAL-012',
status: Status.NOT_STARTED status: PentestStatus.NOT_STARTED
}, },
{ {
category: Category.INPUT_VALIDATION_TESTING, category: Category.INPUT_VALIDATION_TESTING,
refNumber: 'OTG-INPVAL-013', refNumber: 'OTG-INPVAL-013',
status: Status.NOT_STARTED, status: PentestStatus.NOT_STARTED,
childEntries: [ childEntries: [
{ {
category: Category.INPUT_VALIDATION_TESTING, category: Category.INPUT_VALIDATION_TESTING,
refNumber: 'OTG-INPVAL-013_1', refNumber: 'OTG-INPVAL-013_1',
status: Status.NOT_STARTED status: PentestStatus.NOT_STARTED
}, },
{ {
category: Category.INPUT_VALIDATION_TESTING, category: Category.INPUT_VALIDATION_TESTING,
refNumber: 'OTG-INPVAL-013_2', refNumber: 'OTG-INPVAL-013_2',
status: Status.NOT_STARTED status: PentestStatus.NOT_STARTED
} }
] ]
}, },
{ {
category: Category.INPUT_VALIDATION_TESTING, category: Category.INPUT_VALIDATION_TESTING,
refNumber: 'OTG-INPVAL-014', refNumber: 'OTG-INPVAL-014',
status: Status.NOT_STARTED status: PentestStatus.NOT_STARTED
}, },
{ {
category: Category.INPUT_VALIDATION_TESTING, category: Category.INPUT_VALIDATION_TESTING,
refNumber: 'OTG-INPVAL-015', refNumber: 'OTG-INPVAL-015',
status: Status.NOT_STARTED, status: PentestStatus.NOT_STARTED,
childEntries: [ childEntries: [
{ {
category: Category.INPUT_VALIDATION_TESTING, category: Category.INPUT_VALIDATION_TESTING,
refNumber: 'OTG-INPVAL-015_1', refNumber: 'OTG-INPVAL-015_1',
status: Status.NOT_STARTED status: PentestStatus.NOT_STARTED
}, },
{ {
category: Category.INPUT_VALIDATION_TESTING, category: Category.INPUT_VALIDATION_TESTING,
refNumber: 'OTG-INPVAL-015_2', refNumber: 'OTG-INPVAL-015_2',
status: Status.NOT_STARTED status: PentestStatus.NOT_STARTED
}, },
{ {
category: Category.INPUT_VALIDATION_TESTING, category: Category.INPUT_VALIDATION_TESTING,
refNumber: 'OTG-INPVAL-015_3', refNumber: 'OTG-INPVAL-015_3',
status: Status.NOT_STARTED status: PentestStatus.NOT_STARTED
} }
] ]
}, },
{ {
category: Category.INPUT_VALIDATION_TESTING, category: Category.INPUT_VALIDATION_TESTING,
refNumber: 'OTG-INPVAL-016', refNumber: 'OTG-INPVAL-016',
status: Status.NOT_STARTED status: PentestStatus.NOT_STARTED
}, },
{ {
category: Category.INPUT_VALIDATION_TESTING, category: Category.INPUT_VALIDATION_TESTING,
refNumber: 'OTG-INPVAL-017', refNumber: 'OTG-INPVAL-017',
status: Status.NOT_STARTED status: PentestStatus.NOT_STARTED
}, },
]; ];
} }

View File

@ -1,48 +1,48 @@
import {Pentest} from '@shared/models/pentest.model'; import {Pentest} from '@shared/models/pentest.model';
import {Category} from '@shared/models/category.model'; import {Category} from '@shared/models/category.model';
import {Status} from '@shared/models/status.model'; import {PentestStatus} from '@shared/models/pentest-status.model';
export function getSESS_Pentests(): Pentest[] { export function getSESS_Pentests(): Pentest[] {
return [ return [
{ {
category: Category.SESSION_MANAGEMENT_TESTING, category: Category.SESSION_MANAGEMENT_TESTING,
refNumber: 'OTG-SESS-001', refNumber: 'OTG-SESS-001',
status: Status.NOT_STARTED status: PentestStatus.NOT_STARTED
}, },
{ {
category: Category.SESSION_MANAGEMENT_TESTING, category: Category.SESSION_MANAGEMENT_TESTING,
refNumber: 'OTG-SESS-002', refNumber: 'OTG-SESS-002',
status: Status.NOT_STARTED status: PentestStatus.NOT_STARTED
}, },
{ {
category: Category.SESSION_MANAGEMENT_TESTING, category: Category.SESSION_MANAGEMENT_TESTING,
refNumber: 'OTG-SESS-003', refNumber: 'OTG-SESS-003',
status: Status.NOT_STARTED status: PentestStatus.NOT_STARTED
}, },
{ {
category: Category.SESSION_MANAGEMENT_TESTING, category: Category.SESSION_MANAGEMENT_TESTING,
refNumber: 'OTG-SESS-004', refNumber: 'OTG-SESS-004',
status: Status.NOT_STARTED status: PentestStatus.NOT_STARTED
}, },
{ {
category: Category.SESSION_MANAGEMENT_TESTING, category: Category.SESSION_MANAGEMENT_TESTING,
refNumber: 'OTG-SESS-005', refNumber: 'OTG-SESS-005',
status: Status.NOT_STARTED status: PentestStatus.NOT_STARTED
}, },
{ {
category: Category.SESSION_MANAGEMENT_TESTING, category: Category.SESSION_MANAGEMENT_TESTING,
refNumber: 'OTG-SESS-006', refNumber: 'OTG-SESS-006',
status: Status.NOT_STARTED status: PentestStatus.NOT_STARTED
}, },
{ {
category: Category.SESSION_MANAGEMENT_TESTING, category: Category.SESSION_MANAGEMENT_TESTING,
refNumber: 'OTG-SESS-007', refNumber: 'OTG-SESS-007',
status: Status.NOT_STARTED status: PentestStatus.NOT_STARTED
}, },
{ {
category: Category.SESSION_MANAGEMENT_TESTING, category: Category.SESSION_MANAGEMENT_TESTING,
refNumber: 'OTG-SESS-008', refNumber: 'OTG-SESS-008',
status: Status.NOT_STARTED status: PentestStatus.NOT_STARTED
} }
]; ];
} }

View File

@ -0,0 +1,7 @@
export enum PentestStatus {
NOT_STARTED = 'NOT_STARTED',
DISABLED = 'DISABLED',
OPEN = 'OPEN',
IN_PROGRESS = 'IN_PROGRESS',
COMPLETED = 'COMPLETED',
}

View File

@ -1,5 +1,5 @@
import {v4 as UUID} from 'uuid'; import {v4 as UUID} from 'uuid';
import {Status} from '@shared/models/status.model'; import {PentestStatus} from '@shared/models/pentest-status.model';
import {Category} from '@shared/models/category.model'; import {Category} from '@shared/models/category.model';
export class Pentest { export class Pentest {
@ -7,13 +7,13 @@ export class Pentest {
category: Category; category: Category;
refNumber: string; refNumber: string;
childEntries?: Pentest[]; childEntries?: Pentest[];
status: Status; status: PentestStatus;
findingsIds?: Array<string>; findingsIds?: Array<string>;
commentsIds?: Array<string>; commentsIds?: Array<string>;
constructor(category: Category, constructor(category: Category,
refNumber: string, refNumber: string,
status: Status, status: PentestStatus,
id?: string, id?: string,
findingsIds?: Array<string>, findingsIds?: Array<string>,
commentsIds?: Array<string>) { commentsIds?: Array<string>) {

View File

@ -1,5 +1,5 @@
export enum Route { export enum Route {
HOME = 'home', HOME = 'home',
PROJECT_OVERVIEW = 'projects', PROJECT_OVERVIEW = 'projects',
PENTEST = 'pentest' PENTEST_OVERVIEW = 'pentest'
} }

View File

@ -1,9 +0,0 @@
export enum Status {
NOT_STARTED = 'NOT_STARTED',
DISABLED = 'DISABLED',
OPEN = 'OPEN',
CHECKED = 'CHECKED',
REPORTED = 'REPORTED',
UNDER_REVIEW = 'UNDER_REVIEW',
TRIAGED = 'TRIAGED'
}

View File

@ -93,6 +93,7 @@ export const mockProject: Project = {
client: 'Testclient', client: 'Testclient',
tester: 'Testpentester', tester: 'Testpentester',
createdAt: new Date(), createdAt: new Date(),
testingProgress: 0,
createdBy: 'UID-11-12-13' createdBy: 'UID-11-12-13'
}; };

View File

@ -41,6 +41,7 @@ describe('ProjectService', () => {
title: 'Some Mock API (v1.0) Scanning', title: 'Some Mock API (v1.0) Scanning',
createdAt: dummyDate, createdAt: dummyDate,
tester: 'Novatester', tester: 'Novatester',
testingProgress: 0,
createdBy: '11c47c56-3bcd-45f1-a05b-c197dbd33110' createdBy: '11c47c56-3bcd-45f1-a05b-c197dbd33110'
}; };
@ -89,6 +90,7 @@ describe('ProjectService', () => {
title: 'Some Mock API (v1.0) Scanning', title: 'Some Mock API (v1.0) Scanning',
createdAt: dummyDate, createdAt: dummyDate,
tester: 'Novatester', tester: 'Novatester',
testingProgress: 0,
createdBy: '11c47c56-3bcd-45f1-a05b-c197dbd33110' createdBy: '11c47c56-3bcd-45f1-a05b-c197dbd33110'
}; };

View File

@ -1,5 +1,6 @@
import {Project} from '@shared/models/project.model'; import {Project} from '@shared/models/project.model';
import {Category} from '@shared/models/category.model'; import {Category} from '@shared/models/category.model';
import {Pentest} from '@shared/models/pentest.model';
export class InitProjectState { export class InitProjectState {
@ -29,6 +30,6 @@ export class ChangeCategory {
export class ChangePentest { export class ChangePentest {
static readonly type = '[ProjectState] ChangePentest'; static readonly type = '[ProjectState] ChangePentest';
constructor(public pentestId: string) { constructor(public pentest: Pentest) {
} }
} }

View File

@ -12,7 +12,7 @@ const INITIAL_PROJECT_STATE_SESSION: ProjectStateModel = {
disabledCategories: [], disabledCategories: [],
selectedCategory: Category.INFORMATION_GATHERING, selectedCategory: Category.INFORMATION_GATHERING,
disabledPentests: [], disabledPentests: [],
selectedPentestId: null selectedPentest: null
}; };
const DESIRED_PROJECT_STATE_SESSION: ProjectStateModel = { const DESIRED_PROJECT_STATE_SESSION: ProjectStateModel = {
@ -20,7 +20,7 @@ const DESIRED_PROJECT_STATE_SESSION: ProjectStateModel = {
disabledCategories: [], disabledCategories: [],
selectedCategory: Category.INFORMATION_GATHERING, selectedCategory: Category.INFORMATION_GATHERING,
disabledPentests: [], disabledPentests: [],
selectedPentestId: null selectedPentest: null
}; };
describe('SessionState', () => { describe('SessionState', () => {

View File

@ -3,6 +3,7 @@ import {Injectable} from '@angular/core';
import {Project} from '@shared/models/project.model'; import {Project} from '@shared/models/project.model';
import {ChangeCategory, ChangePentest, ChangeProject, InitProjectState} from '@shared/stores/project-state/project-state.actions'; import {ChangeCategory, ChangePentest, ChangeProject, InitProjectState} from '@shared/stores/project-state/project-state.actions';
import {Category} from '@shared/models/category.model'; import {Category} from '@shared/models/category.model';
import {Pentest} from '@shared/models/pentest.model';
export const PROJECT_STATE_NAME = 'project'; export const PROJECT_STATE_NAME = 'project';
@ -13,7 +14,7 @@ export interface ProjectStateModel {
selectedCategory: Category; selectedCategory: Category;
// Manages Pentests of Category // Manages Pentests of Category
disabledPentests: Array<string>; disabledPentests: Array<string>;
selectedPentestId: string; selectedPentest: Pentest;
} }
@State<ProjectStateModel>({ @State<ProjectStateModel>({
@ -23,7 +24,7 @@ export interface ProjectStateModel {
disabledCategories: [], disabledCategories: [],
selectedCategory: Category.INFORMATION_GATHERING, selectedCategory: Category.INFORMATION_GATHERING,
disabledPentests: [], disabledPentests: [],
selectedPentestId: null selectedPentest: null
} }
}) })
@Injectable() @Injectable()
@ -39,8 +40,8 @@ export class ProjectState {
} }
@Selector() @Selector()
static selectedPentestId(state: ProjectStateModel): string { static pentest(state: ProjectStateModel): Pentest {
return state.selectedPentestId; return state.selectedPentest;
} }
@Action(InitProjectState) @Action(InitProjectState)
@ -50,7 +51,7 @@ export class ProjectState {
disabledCategories: action.disabledCategories, disabledCategories: action.disabledCategories,
selectedCategory: Category.INFORMATION_GATHERING, selectedCategory: Category.INFORMATION_GATHERING,
disabledPentests: action.disabledPentests, disabledPentests: action.disabledPentests,
selectedPentestId: null selectedPentest: null
}); });
} }
@ -73,10 +74,10 @@ export class ProjectState {
} }
@Action(ChangePentest) @Action(ChangePentest)
changePentest(ctx: StateContext<ProjectStateModel>, {pentestId}: ChangePentest): void { changePentest(ctx: StateContext<ProjectStateModel>, {pentest}: ChangePentest): void {
const state = ctx.getState(); const state = ctx.getState();
ctx.patchState({ ctx.patchState({
selectedPentestId: pentestId selectedPentest: pentest
}); });
} }
} }

View File

@ -2,13 +2,9 @@
<nb-tag-list> <nb-tag-list>
<nb-tag *ngSwitchCase="status.OPEN" status="info" appearance="filled" <nb-tag *ngSwitchCase="status.OPEN" status="info" appearance="filled"
text="{{getTranslationKey() | translate}}"></nb-tag> text="{{getTranslationKey() | translate}}"></nb-tag>
<nb-tag *ngSwitchCase="status.CHECKED" status="primary" appearance="filled" <nb-tag *ngSwitchCase="status.IN_PROGRESS" status="warning" appearance="filled"
text="{{getTranslationKey() | translate}}"></nb-tag>
<nb-tag *ngSwitchCase="status.REPORTED" status="danger" appearance="filled"
text="{{getTranslationKey() | translate}}"></nb-tag>
<nb-tag *ngSwitchCase="status.UNDER_REVIEW" status="warning" appearance="filled"
text=" {{getTranslationKey() | translate}}"></nb-tag> text=" {{getTranslationKey() | translate}}"></nb-tag>
<nb-tag *ngSwitchCase="status.TRIAGED" status="success" appearance="filled" <nb-tag *ngSwitchCase="status.COMPLETED" status="success" appearance="filled"
text="{{getTranslationKey() | translate}}"></nb-tag> text="{{getTranslationKey() | translate}}"></nb-tag>
<nb-tag *ngSwitchDefault status="basic" appearance="filled" <nb-tag *ngSwitchDefault status="basic" appearance="filled"
text="{{getTranslationKey() | translate}}"></nb-tag> text="{{getTranslationKey() | translate}}"></nb-tag>

View File

@ -1,5 +1,5 @@
import {ChangeDetectionStrategy, Component, Input, OnInit} from '@angular/core'; import {ChangeDetectionStrategy, Component, Input, OnInit} from '@angular/core';
import {Status} from '@shared/models/status.model'; import {PentestStatus} from '@shared/models/pentest-status.model';
@Component({ @Component({
selector: 'app-status-tag', selector: 'app-status-tag',
@ -8,18 +8,16 @@ import {Status} from '@shared/models/status.model';
changeDetection: ChangeDetectionStrategy.OnPush, changeDetection: ChangeDetectionStrategy.OnPush,
}) })
export class StatusTagComponent implements OnInit { export class StatusTagComponent implements OnInit {
@Input() currentStatus: Status = Status.NOT_STARTED; @Input() currentStatus: PentestStatus = PentestStatus.NOT_STARTED;
// HTML only // HTML only
status = Status; status = PentestStatus;
readonly statusTexts: Array<StatusText> = [ readonly statusTexts: Array<StatusText> = [
{value: Status.NOT_STARTED, translationText: 'pentest.statusText.not_started'}, {value: PentestStatus.NOT_STARTED, translationText: 'pentest.statusText.not_started'},
{value: Status.DISABLED, translationText: 'pentest.statusText.disabled'}, {value: PentestStatus.DISABLED, translationText: 'pentest.statusText.disabled'},
{value: Status.OPEN, translationText: 'pentest.statusText.open'}, {value: PentestStatus.OPEN, translationText: 'pentest.statusText.open'},
{value: Status.CHECKED, translationText: 'pentest.statusText.checked'}, {value: PentestStatus.IN_PROGRESS, translationText: 'pentest.statusText.in_progress'},
{value: Status.REPORTED, translationText: 'pentest.statusText.reported'}, {value: PentestStatus.COMPLETED, translationText: 'pentest.statusText.completed'}
{value: Status.UNDER_REVIEW, translationText: 'pentest.statusText.under_review'},
{value: Status.TRIAGED, translationText: 'pentest.statusText.triaged'}
]; ];
constructor() { } constructor() { }

View File

@ -3,9 +3,6 @@ package com.securityc4po.api.pentest
enum class PentestStatus { enum class PentestStatus {
NOT_STARTED, NOT_STARTED,
OPEN, OPEN,
UNDER_REVIEW, IN_PROGRESS,
DISABLED, COMPLETED
CHECKED,
REPORTED,
TRIAGED
} }

View File

@ -3,6 +3,7 @@ package com.securityc4po.api.project
import com.fasterxml.jackson.annotation.JsonFormat import com.fasterxml.jackson.annotation.JsonFormat
import com.securityc4po.api.ResponseBody import com.securityc4po.api.ResponseBody
import com.securityc4po.api.pentest.PentestStatus import com.securityc4po.api.pentest.PentestStatus
import org.springframework.beans.factory.annotation.Value
import org.springframework.data.mongodb.core.index.Indexed import org.springframework.data.mongodb.core.index.Indexed
import java.math.RoundingMode import java.math.RoundingMode
import java.text.DecimalFormat import java.text.DecimalFormat
@ -52,9 +53,13 @@ fun Project.toProjectDeleteResponseBody(): ResponseBody {
) )
} }
fun Project.calculateProgress(): Float { fun Project.calculateProgress(): Float {
// Total number of pentests listet in the OWASP testing guide // Total number of pentests listet in the OWASP testing guide
// https://owasp.org/www-project-web-security-testing-guide/assets/archive/OWASP_Testing_Guide_v4.pdf // https://owasp.org/www-project-web-security-testing-guide/assets/archive/OWASP_Testing_Guide_v4.pdf
// @Value("\${owasp.web.pentests}")
// lateinit var TOTALPENTESTS: Int
val TOTALPENTESTS = 95 val TOTALPENTESTS = 95
return if (projectPentests.isEmpty()) return if (projectPentests.isEmpty())
@ -62,7 +67,7 @@ fun Project.calculateProgress(): Float {
else { else {
var completedPentests = 0 var completedPentests = 0
projectPentests.forEach { projectPentest -> projectPentests.forEach { projectPentest ->
if (projectPentest.status == PentestStatus.TRIAGED) { if (projectPentest.status == PentestStatus.COMPLETED) {
completedPentests++ completedPentests++
} }
} }

View File

@ -20,3 +20,7 @@ spring.security.oauth2.resourceserver.jwt.issuer-uri=http://localhost:8888/auth/
keycloakhost=localhost keycloakhost=localhost
keycloak.client.url=http://localhost:8888 keycloak.client.url=http://localhost:8888
keycloak.client.realm.path=auth/realms/c4po_realm_local/ keycloak.client.realm.path=auth/realms/c4po_realm_local/
## Total number of pentests listet in the OWASP testing guide
## https://owasp.org/www-project-web-security-testing-guide/assets/archive/OWASP_Testing_Guide_v4.pdf
owasp.web.pentests=95

View File

@ -106,7 +106,7 @@ class PentestControllerDocumentationTest : BaseDocumentationIntTest() {
category = PentestCategory.INFORMATION_GATHERING, category = PentestCategory.INFORMATION_GATHERING,
title = "Fingerprint Web Server", title = "Fingerprint Web Server",
refNumber = "OTG-INFO-002", refNumber = "OTG-INFO-002",
status = PentestStatus.REPORTED, status = PentestStatus.IN_PROGRESS,
findingIds = emptyList(), findingIds = emptyList(),
commentIds = emptyList() commentIds = emptyList()
) )
@ -135,7 +135,7 @@ class PentestControllerDocumentationTest : BaseDocumentationIntTest() {
category = PentestCategory.INFORMATION_GATHERING, category = PentestCategory.INFORMATION_GATHERING,
title = "Fingerprint Web Server", title = "Fingerprint Web Server",
refNumber = "OTG-INFO-002", refNumber = "OTG-INFO-002",
status = PentestStatus.REPORTED, status = PentestStatus.IN_PROGRESS,
findingIds = emptyList(), findingIds = emptyList(),
commentIds = emptyList() commentIds = emptyList()
) )
@ -145,7 +145,7 @@ class PentestControllerDocumentationTest : BaseDocumentationIntTest() {
category = PentestCategory.AUTHENTICATION_TESTING, category = PentestCategory.AUTHENTICATION_TESTING,
title = "Testing for Credentials Transported over an Encrypted Channel", title = "Testing for Credentials Transported over an Encrypted Channel",
refNumber = "OTG-AUTHN-001", refNumber = "OTG-AUTHN-001",
status = PentestStatus.CHECKED, status = PentestStatus.COMPLETED,
findingIds = emptyList(), findingIds = emptyList(),
commentIds = emptyList() commentIds = emptyList()
) )

View File

@ -81,7 +81,7 @@ class PentestControllerIntTest : BaseIntTest() {
category = PentestCategory.INFORMATION_GATHERING, category = PentestCategory.INFORMATION_GATHERING,
title = "Fingerprint Web Server", title = "Fingerprint Web Server",
refNumber = "OTG-INFO-002", refNumber = "OTG-INFO-002",
status = PentestStatus.REPORTED, status = PentestStatus.IN_PROGRESS,
findingIds = emptyList(), findingIds = emptyList(),
commentIds = emptyList() commentIds = emptyList()
) )
@ -110,7 +110,7 @@ class PentestControllerIntTest : BaseIntTest() {
category = PentestCategory.INFORMATION_GATHERING, category = PentestCategory.INFORMATION_GATHERING,
title = "Fingerprint Web Server", title = "Fingerprint Web Server",
refNumber = "OTG-INFO-002", refNumber = "OTG-INFO-002",
status = PentestStatus.REPORTED, status = PentestStatus.COMPLETED,
findingIds = emptyList(), findingIds = emptyList(),
commentIds = emptyList() commentIds = emptyList()
) )
@ -120,7 +120,7 @@ class PentestControllerIntTest : BaseIntTest() {
category = PentestCategory.AUTHENTICATION_TESTING, category = PentestCategory.AUTHENTICATION_TESTING,
title = "Testing for Credentials Transported over an Encrypted Channel", title = "Testing for Credentials Transported over an Encrypted Channel",
refNumber = "OTG-AUTHN-001", refNumber = "OTG-AUTHN-001",
status = PentestStatus.CHECKED, status = PentestStatus.COMPLETED,
findingIds = emptyList(), findingIds = emptyList(),
commentIds = emptyList() commentIds = emptyList()
) )