feat: added pentest table and added ngrx store for project management
This commit is contained in:
parent
501a6d3427
commit
f7ac93a7eb
|
@ -1,5 +1,5 @@
|
||||||
# base image
|
# base image
|
||||||
FROM node:12.13.1
|
FROM node:14.15.3
|
||||||
|
|
||||||
# set working directory
|
# set working directory
|
||||||
WORKDIR /app
|
WORKDIR /app
|
||||||
|
@ -10,7 +10,7 @@ ENV PATH /app/node_modules/.bin:$PATH
|
||||||
# install and cache app dependencies
|
# install and cache app dependencies
|
||||||
COPY package.json /app/package.json
|
COPY package.json /app/package.json
|
||||||
RUN npm install
|
RUN npm install
|
||||||
RUN npm install -g @angular/cli@10.2.0
|
RUN npm install -g @angular/cli@12.2.17
|
||||||
|
|
||||||
# add app
|
# add app
|
||||||
COPY . /app
|
COPY . /app
|
||||||
|
|
|
@ -22,7 +22,6 @@
|
||||||
"main": "src/main.ts",
|
"main": "src/main.ts",
|
||||||
"polyfills": "src/polyfills.ts",
|
"polyfills": "src/polyfills.ts",
|
||||||
"tsConfig": "tsconfig.app.json",
|
"tsConfig": "tsconfig.app.json",
|
||||||
"aot": true,
|
|
||||||
"assets": [
|
"assets": [
|
||||||
"src/assets/images/favicons/favicon.ico",
|
"src/assets/images/favicons/favicon.ico",
|
||||||
"src/assets/images/favicons/corporate_favicon.ico",
|
"src/assets/images/favicons/corporate_favicon.ico",
|
||||||
|
@ -40,7 +39,13 @@
|
||||||
"deep-equal",
|
"deep-equal",
|
||||||
"moment-timezone",
|
"moment-timezone",
|
||||||
"uuid"
|
"uuid"
|
||||||
]
|
],
|
||||||
|
"vendorChunk": true,
|
||||||
|
"extractLicenses": false,
|
||||||
|
"buildOptimizer": false,
|
||||||
|
"sourceMap": true,
|
||||||
|
"optimization": false,
|
||||||
|
"namedChunks": true
|
||||||
},
|
},
|
||||||
"configurations": {
|
"configurations": {
|
||||||
"production": {
|
"production": {
|
||||||
|
@ -53,9 +58,7 @@
|
||||||
"optimization": true,
|
"optimization": true,
|
||||||
"outputHashing": "all",
|
"outputHashing": "all",
|
||||||
"sourceMap": false,
|
"sourceMap": false,
|
||||||
"extractCss": true,
|
|
||||||
"namedChunks": false,
|
"namedChunks": false,
|
||||||
"aot": true,
|
|
||||||
"extractLicenses": true,
|
"extractLicenses": true,
|
||||||
"vendorChunk": false,
|
"vendorChunk": false,
|
||||||
"buildOptimizer": true,
|
"buildOptimizer": true,
|
||||||
|
@ -71,7 +74,8 @@
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
|
"defaultConfiguration": ""
|
||||||
},
|
},
|
||||||
"serve": {
|
"serve": {
|
||||||
"builder": "@angular-devkit/build-angular:dev-server",
|
"builder": "@angular-devkit/build-angular:dev-server",
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -11,55 +11,56 @@
|
||||||
},
|
},
|
||||||
"private": true,
|
"private": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@angular/animations": "^11.0.3",
|
"@angular/animations": "^12.2.16",
|
||||||
"@angular/cdk": "^10.2.7",
|
"@angular/cdk": "^12.2.7",
|
||||||
"@angular/common": "^10.2.3",
|
"@angular/common": "^12.2.16",
|
||||||
"@angular/compiler": "~10.2.0",
|
"@angular/compiler": "~12.2.16",
|
||||||
"@angular/core": "~10.2.0",
|
"@angular/core": "~12.2.16",
|
||||||
"@angular/flex-layout": "^11.0.0-beta.33",
|
"@angular/flex-layout": "^11.0.0-beta.33",
|
||||||
"@angular/forms": "~10.2.0",
|
"@angular/forms": "~12.2.16",
|
||||||
"@angular/localize": "^11.0.2",
|
"@angular/localize": "^12.2.16",
|
||||||
"@angular/platform-browser": "~10.2.0",
|
"@angular/platform-browser": "~12.2.16",
|
||||||
"@angular/platform-browser-dynamic": "~10.2.0",
|
"@angular/platform-browser-dynamic": "~12.2.16",
|
||||||
"@angular/router": "~10.2.0",
|
"@angular/router": "~12.2.16",
|
||||||
"@briebug/jest-schematic": "^3.0.0",
|
"@briebug/jest-schematic": "^3.0.0",
|
||||||
"@fortawesome/angular-fontawesome": "^0.8.0",
|
"@fortawesome/angular-fontawesome": "^0.8.2",
|
||||||
"@fortawesome/fontawesome-common-types": "^0.2.32",
|
"@fortawesome/fontawesome-common-types": "^0.2.36",
|
||||||
"@fortawesome/fontawesome-svg-core": "^1.2.32",
|
"@fortawesome/fontawesome-svg-core": "^1.2.36",
|
||||||
"@fortawesome/free-regular-svg-icons": "^5.15.1",
|
"@fortawesome/free-regular-svg-icons": "^5.15.4",
|
||||||
"@fortawesome/free-solid-svg-icons": "^5.15.1",
|
"@fortawesome/free-solid-svg-icons": "^5.15.4",
|
||||||
"@nebular/eva-icons": "^6.2.1",
|
"@nebular/eva-icons": "^8.0.0",
|
||||||
"@nebular/theme": "^6.2.1",
|
"@nebular/theme": "^8.0.0",
|
||||||
"@ngx-translate/core": "^13.0.0",
|
"@ngx-translate/core": "^13.0.0",
|
||||||
"@ngx-translate/http-loader": "^6.0.0",
|
"@ngx-translate/http-loader": "^6.0.0",
|
||||||
"@ngxs/store": "^3.7.0",
|
"@ngxs/store": "^3.7.3",
|
||||||
"eva-icons": "^1.1.3",
|
"eva-icons": "^1.1.3",
|
||||||
"i18n-iso-countries": "^6.2.2",
|
"i18n-iso-countries": "^6.8.0",
|
||||||
"jwt-decode": "^3.1.2",
|
"jwt-decode": "^3.1.2",
|
||||||
"keycloak-angular": "^8.1.0",
|
"keycloak-angular": "^8.4.0",
|
||||||
"keycloak-js": "^13.0.0",
|
"keycloak-js": "^13.0.1",
|
||||||
"moment": "^2.29.1",
|
"moment": "^2.29.1",
|
||||||
"moment-timezone": "latest",
|
"moment-timezone": "latest",
|
||||||
|
"ng-mocks": "^13.4.2",
|
||||||
"ngx-moment": "^5.0.0",
|
"ngx-moment": "^5.0.0",
|
||||||
"ngx-take-until-destroy": "^5.4.0",
|
"ngx-take-until-destroy": "^5.4.0",
|
||||||
"ngx-translate-testing": "^5.0.0",
|
"ngx-translate-testing": "^5.2.0",
|
||||||
"roboto-fontface": "^0.10.0",
|
"roboto-fontface": "^0.10.0",
|
||||||
"rxjs": "~6.6.0",
|
"rxjs": "^6.6.7",
|
||||||
"tslib": "^2.0.0",
|
"tslib": "^2.3.1",
|
||||||
"uuid": "^8.3.1",
|
"uuid": "^8.3.2",
|
||||||
"zone.js": "~0.10.2"
|
"zone.js": "~0.11.4"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@angular-builders/jest": "10.0.1",
|
"@angular-builders/jest": "10.0.1",
|
||||||
"@angular-devkit/build-angular": "~0.1002.0",
|
"@angular-devkit/build-angular": "~12.2.16",
|
||||||
"@angular/cli": "~10.2.0",
|
"@angular/cli": "~12.2.16",
|
||||||
"@angular/compiler-cli": "~10.2.0",
|
"@angular/compiler-cli": "~12.2.16",
|
||||||
"@schematics/angular": "~10.2.0",
|
"@schematics/angular": "^10.2.4",
|
||||||
"@types/jasmine": "~3.5.0",
|
"@types/jasmine": "~3.6.0",
|
||||||
"@types/jasminewd2": "~2.0.3",
|
"@types/jasminewd2": "^2.0.10",
|
||||||
"@types/jest": "26.0.15",
|
"@types/jest": "26.0.15",
|
||||||
"@types/node": "^12.20.33",
|
"@types/node": "^12.20.47",
|
||||||
"codelyzer": "^6.0.0",
|
"codelyzer": "^6.0.2",
|
||||||
"font-awesome": "^4.7.0",
|
"font-awesome": "^4.7.0",
|
||||||
"jasmine-core": "~3.6.0",
|
"jasmine-core": "~3.6.0",
|
||||||
"jasmine-spec-reporter": "~5.0.0",
|
"jasmine-spec-reporter": "~5.0.0",
|
||||||
|
@ -67,6 +68,9 @@
|
||||||
"protractor": "~7.0.0",
|
"protractor": "~7.0.0",
|
||||||
"ts-node": "~8.3.0",
|
"ts-node": "~8.3.0",
|
||||||
"tslint": "~6.1.0",
|
"tslint": "~6.1.0",
|
||||||
"typescript": "~4.0.2"
|
"typescript": "~4.3.5"
|
||||||
|
},
|
||||||
|
"resolutions": {
|
||||||
|
"webpack": "^5.0.0"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -27,7 +27,7 @@ const routes: Routes = [
|
||||||
];
|
];
|
||||||
|
|
||||||
@NgModule({
|
@NgModule({
|
||||||
imports: [RouterModule.forRoot(routes)],
|
imports: [RouterModule.forRoot(routes, { relativeLinkResolution: 'legacy' })],
|
||||||
exports: [RouterModule]
|
exports: [RouterModule]
|
||||||
})
|
})
|
||||||
export class AppRoutingModule { }
|
export class AppRoutingModule { }
|
||||||
|
|
|
@ -29,6 +29,8 @@ import {FlexLayoutModule} from '@angular/flex-layout';
|
||||||
import {DialogService} from '@shared/services/dialog-service/dialog.service';
|
import {DialogService} from '@shared/services/dialog-service/dialog.service';
|
||||||
import {ConfirmDialogModule} from '@shared/modules/confirm-dialog/confirm-dialog.module';
|
import {ConfirmDialogModule} from '@shared/modules/confirm-dialog/confirm-dialog.module';
|
||||||
import {OverlayContainer} from '@angular/cdk/overlay';
|
import {OverlayContainer} from '@angular/cdk/overlay';
|
||||||
|
import {NgxsLoggerPluginModule} from '@shared/stores/plugins/store-logger-plugin';
|
||||||
|
import {ProjectState} from '@shared/stores/project-state/project-state';
|
||||||
|
|
||||||
@NgModule({
|
@NgModule({
|
||||||
declarations: [
|
declarations: [
|
||||||
|
@ -50,7 +52,8 @@ import {OverlayContainer} from '@angular/cdk/overlay';
|
||||||
NbEvaIconsModule,
|
NbEvaIconsModule,
|
||||||
NbSelectModule,
|
NbSelectModule,
|
||||||
ConfirmDialogModule,
|
ConfirmDialogModule,
|
||||||
NgxsModule.forRoot([SessionState], {developmentMode: !environment.production}),
|
NgxsModule.forRoot([SessionState, ProjectState], {developmentMode: !environment.production}),
|
||||||
|
NgxsLoggerPluginModule.forRoot({developmentMode: !environment.production}),
|
||||||
HttpClientModule,
|
HttpClientModule,
|
||||||
TranslateModule.forRoot({
|
TranslateModule.forRoot({
|
||||||
loader: {
|
loader: {
|
||||||
|
|
|
@ -3,12 +3,13 @@ import {ComponentFixture, TestBed} from '@angular/core/testing';
|
||||||
import {HeaderComponent} from './header.component';
|
import {HeaderComponent} from './header.component';
|
||||||
import {CommonModule} from '@angular/common';
|
import {CommonModule} from '@angular/common';
|
||||||
import {FontAwesomeTestingModule} from '@fortawesome/angular-fontawesome/testing';
|
import {FontAwesomeTestingModule} from '@fortawesome/angular-fontawesome/testing';
|
||||||
import {NbActionsModule} from '@nebular/theme';
|
import {NbActionsModule, NbSelectModule} from '@nebular/theme';
|
||||||
import {ThemeModule} from '@assets/@theme/theme.module';
|
import {ThemeModule} from '@assets/@theme/theme.module';
|
||||||
import {TranslateLoader, TranslateModule} from '@ngx-translate/core';
|
import {TranslateLoader, TranslateModule} from '@ngx-translate/core';
|
||||||
import {HttpLoaderFactory} from '../common-app.module';
|
import {HttpLoaderFactory} from '../common-app.module';
|
||||||
import {HttpClient} from '@angular/common/http';
|
import {HttpClient} from '@angular/common/http';
|
||||||
import {RouterTestingModule} from '@angular/router/testing';
|
import {RouterTestingModule} from '@angular/router/testing';
|
||||||
|
import {HttpClientTestingModule} from '@angular/common/http/testing';
|
||||||
|
|
||||||
describe('HeaderComponent', () => {
|
describe('HeaderComponent', () => {
|
||||||
let component: HeaderComponent;
|
let component: HeaderComponent;
|
||||||
|
@ -22,7 +23,9 @@ describe('HeaderComponent', () => {
|
||||||
imports: [
|
imports: [
|
||||||
CommonModule,
|
CommonModule,
|
||||||
NbActionsModule,
|
NbActionsModule,
|
||||||
|
NbSelectModule,
|
||||||
FontAwesomeTestingModule,
|
FontAwesomeTestingModule,
|
||||||
|
HttpClientTestingModule,
|
||||||
ThemeModule.forRoot(),
|
ThemeModule.forRoot(),
|
||||||
TranslateModule.forRoot({
|
TranslateModule.forRoot({
|
||||||
loader: {
|
loader: {
|
||||||
|
|
|
@ -1,9 +1,8 @@
|
||||||
import {NgModule} from '@angular/core';
|
import {NgModule} from '@angular/core';
|
||||||
import {CommonModule} from '@angular/common';
|
|
||||||
import {RouterModule, Routes} from '@angular/router';
|
import {RouterModule, Routes} from '@angular/router';
|
||||||
import {ProjectComponent} from '../project-overview/project/project.component';
|
|
||||||
|
|
||||||
const routes: Routes = [];
|
const routes: Routes = [
|
||||||
|
];
|
||||||
|
|
||||||
@NgModule({
|
@NgModule({
|
||||||
imports: [RouterModule.forChild(routes)],
|
imports: [RouterModule.forChild(routes)],
|
||||||
|
|
|
@ -3,7 +3,11 @@ import {CommonModule} from '@angular/common';
|
||||||
import {PentestHeaderComponent} from './pentest-header/pentest-header.component';
|
import {PentestHeaderComponent} from './pentest-header/pentest-header.component';
|
||||||
import {PentestCategoriesComponent} from './pentest-categories/pentest-categories.component';
|
import {PentestCategoriesComponent} from './pentest-categories/pentest-categories.component';
|
||||||
import {PentestTableComponent} from './pentest-table/pentest-table.component';
|
import {PentestTableComponent} from './pentest-table/pentest-table.component';
|
||||||
import {NbLayoutModule} from '@nebular/theme';
|
import {NbCardModule, NbLayoutModule, NbTreeGridModule} from '@nebular/theme';
|
||||||
|
import {TranslateModule} from '@ngx-translate/core';
|
||||||
|
import {StatusTagModule} from '@shared/widgets/status-tag/status-tag.module';
|
||||||
|
import {FindigWidgetModule} from '@shared/widgets/findig-widget/findig-widget.module';
|
||||||
|
import {RouterModule} from '@angular/router';
|
||||||
|
|
||||||
@NgModule({
|
@NgModule({
|
||||||
declarations: [
|
declarations: [
|
||||||
|
@ -18,7 +22,13 @@ import {NbLayoutModule} from '@nebular/theme';
|
||||||
],
|
],
|
||||||
imports: [
|
imports: [
|
||||||
CommonModule,
|
CommonModule,
|
||||||
NbLayoutModule
|
NbLayoutModule,
|
||||||
|
NbCardModule,
|
||||||
|
NbTreeGridModule,
|
||||||
|
TranslateModule,
|
||||||
|
StatusTagModule,
|
||||||
|
FindigWidgetModule,
|
||||||
|
RouterModule
|
||||||
]
|
]
|
||||||
})
|
})
|
||||||
export class PentestOverviewModule {
|
export class PentestOverviewModule {
|
||||||
|
|
|
@ -1 +1,54 @@
|
||||||
<p>pentest-table works!</p>
|
<nb-card class="pentest-table">
|
||||||
|
<table [nbTreeGrid]="dataSource">
|
||||||
|
<tr nbTreeGridHeaderRow *nbTreeGridHeaderRowDef="columns"></tr>
|
||||||
|
<tr nbTreeGridRow *nbTreeGridRowDef="let pentest; columns: columns"
|
||||||
|
class="pentest-cell"
|
||||||
|
routerLink="pentest"
|
||||||
|
fragment="{{pentest.data['refNumber']}}"
|
||||||
|
[skipLocationChange]="true">
|
||||||
|
</tr>
|
||||||
|
<!-- Test ID -->
|
||||||
|
<ng-container [nbTreeGridColumnDef]="columns[0]">
|
||||||
|
<th nbTreeGridHeaderCell *nbTreeGridHeaderCellDef>
|
||||||
|
{{ 'pentest.testId' | translate }}
|
||||||
|
</th>
|
||||||
|
<td nbTreeGridCell *nbTreeGridCellDef="let pentest">
|
||||||
|
<!-- Opens sub categories if row needs to be extendend -->
|
||||||
|
<nb-tree-grid-row-toggle
|
||||||
|
[expanded]="pentest.expanded"
|
||||||
|
*ngIf="pentest.data?.childEntries?.length > 0">
|
||||||
|
</nb-tree-grid-row-toggle>
|
||||||
|
<!---->
|
||||||
|
{{pentest.data['refNumber'] || '-'}}
|
||||||
|
</td>
|
||||||
|
</ng-container>
|
||||||
|
<!-- Title -->
|
||||||
|
<ng-container [nbTreeGridColumnDef]="columns[1]">
|
||||||
|
<th nbTreeGridHeaderCell *nbTreeGridHeaderCellDef>
|
||||||
|
{{ 'pentest.title' | translate }}
|
||||||
|
</th>
|
||||||
|
<td nbTreeGridCell *nbTreeGridCellDef="let pentest">
|
||||||
|
{{ getTitle(pentest.data['refNumber']) | translate }}
|
||||||
|
</td>
|
||||||
|
</ng-container>
|
||||||
|
<!-- Status -->
|
||||||
|
<ng-container [nbTreeGridColumnDef]="columns[2]">
|
||||||
|
<th nbTreeGridHeaderCell *nbTreeGridHeaderCellDef>
|
||||||
|
{{ 'pentest.status' | translate }}
|
||||||
|
</th>
|
||||||
|
<td nbTreeGridCell *nbTreeGridCellDef="let pentest">
|
||||||
|
<app-status-tag [currentStatus]="pentest.data['status']"></app-status-tag>
|
||||||
|
</td>
|
||||||
|
</ng-container>
|
||||||
|
<!-- Findings -->
|
||||||
|
<ng-container [nbTreeGridColumnDef]="columns[3]">
|
||||||
|
<th nbTreeGridHeaderCell *nbTreeGridHeaderCellDef>
|
||||||
|
{{ 'pentest.findings' | translate }}
|
||||||
|
</th>
|
||||||
|
<td nbTreeGridCell *nbTreeGridCellDef="let pentest">
|
||||||
|
<app-findig-widget [numberOfFindigs]="pentest.data['findings']"></app-findig-widget>
|
||||||
|
<!--{{pentest.data['findings'] || '-'}}-->
|
||||||
|
</td>
|
||||||
|
</ng-container>
|
||||||
|
</table>
|
||||||
|
</nb-card>
|
||||||
|
|
|
@ -0,0 +1,13 @@
|
||||||
|
@import '../../../assets/@theme/styles/themes';
|
||||||
|
|
||||||
|
.pentest-table {
|
||||||
|
|
||||||
|
.pentest-cell {
|
||||||
|
// Add style here
|
||||||
|
}
|
||||||
|
|
||||||
|
.pentest-cell:hover {
|
||||||
|
cursor: pointer;
|
||||||
|
background-color: nb-theme(color-basic-transparent-focus);
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,6 +1,19 @@
|
||||||
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
import {ComponentFixture, TestBed} from '@angular/core/testing';
|
||||||
|
|
||||||
import { PentestTableComponent } from './pentest-table.component';
|
import {PentestTableComponent} from './pentest-table.component';
|
||||||
|
import {NbCardModule, NbTreeGridModule} from '@nebular/theme';
|
||||||
|
import {TranslateLoader, TranslateModule} from '@ngx-translate/core';
|
||||||
|
import {HttpLoaderFactory} from '../../common-app.module';
|
||||||
|
import {HttpClient} from '@angular/common/http';
|
||||||
|
import {BrowserAnimationsModule} from '@angular/platform-browser/animations';
|
||||||
|
import {ThemeModule} from '@assets/@theme/theme.module';
|
||||||
|
import {RouterTestingModule} from '@angular/router/testing';
|
||||||
|
import {StatusTagComponent} from '@shared/widgets/status-tag/status-tag.component';
|
||||||
|
import {FindigWidgetComponent} from '@shared/widgets/findig-widget/findig-widget.component';
|
||||||
|
import {MockComponent} from 'ng-mocks';
|
||||||
|
import {NgxsModule} from '@ngxs/store';
|
||||||
|
import {ProjectState} from '@shared/stores/project-state/project-state';
|
||||||
|
import {HttpClientTestingModule} from '@angular/common/http/testing';
|
||||||
|
|
||||||
describe('PentestTableComponent', () => {
|
describe('PentestTableComponent', () => {
|
||||||
let component: PentestTableComponent;
|
let component: PentestTableComponent;
|
||||||
|
@ -8,9 +21,29 @@ describe('PentestTableComponent', () => {
|
||||||
|
|
||||||
beforeEach(async () => {
|
beforeEach(async () => {
|
||||||
await TestBed.configureTestingModule({
|
await TestBed.configureTestingModule({
|
||||||
declarations: [ PentestTableComponent ]
|
declarations: [
|
||||||
|
PentestTableComponent,
|
||||||
|
MockComponent(StatusTagComponent),
|
||||||
|
MockComponent(FindigWidgetComponent)
|
||||||
|
],
|
||||||
|
imports: [
|
||||||
|
BrowserAnimationsModule,
|
||||||
|
HttpClientTestingModule,
|
||||||
|
NbCardModule,
|
||||||
|
NbTreeGridModule,
|
||||||
|
ThemeModule.forRoot(),
|
||||||
|
TranslateModule.forRoot({
|
||||||
|
loader: {
|
||||||
|
provide: TranslateLoader,
|
||||||
|
useFactory: HttpLoaderFactory,
|
||||||
|
deps: [HttpClient]
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
RouterTestingModule.withRoutes([]),
|
||||||
|
NgxsModule.forRoot([ProjectState])
|
||||||
|
]
|
||||||
})
|
})
|
||||||
.compileComponents();
|
.compileComponents();
|
||||||
});
|
});
|
||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
|
|
|
@ -1,15 +1,74 @@
|
||||||
import { Component, OnInit } from '@angular/core';
|
import {Component, OnDestroy, OnInit} from '@angular/core';
|
||||||
|
import {NbGetters, NbTreeGridDataSource, NbTreeGridDataSourceBuilder} from '@nebular/theme';
|
||||||
|
import {Pentest, PentestEntry, transformPentestsToEntries} from '@shared/models/pentest.model';
|
||||||
|
import {PentestService} from '@shared/services/pentest.service';
|
||||||
|
import {Store} from '@ngxs/store';
|
||||||
|
import {ProjectState} from '@shared/stores/project-state/project-state';
|
||||||
|
import {untilDestroyed} from 'ngx-take-until-destroy';
|
||||||
|
import {catchError, switchMap} from 'rxjs/operators';
|
||||||
|
import {of} from 'rxjs';
|
||||||
|
import {getTitleKeyForRefNumber} from '@shared/functions/categories/get-title-key-for-ref-number.function';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-pentest-table',
|
selector: 'app-pentest-table',
|
||||||
templateUrl: './pentest-table.component.html',
|
templateUrl: './pentest-table.component.html',
|
||||||
styleUrls: ['./pentest-table.component.scss']
|
styleUrls: ['./pentest-table.component.scss']
|
||||||
})
|
})
|
||||||
export class PentestTableComponent implements OnInit {
|
export class PentestTableComponent implements OnInit, OnDestroy {
|
||||||
|
|
||||||
constructor() { }
|
columns: Array<PentestColumns> = [PentestColumns.TEST_ID, PentestColumns.TITLE, PentestColumns.STATUS, PentestColumns.FINDINGS];
|
||||||
|
dataSource: NbTreeGridDataSource<PentestEntry>;
|
||||||
|
|
||||||
ngOnInit(): void {
|
private data: PentestEntry[] = [];
|
||||||
|
|
||||||
|
getters: NbGetters<PentestEntry, PentestEntry> = {
|
||||||
|
dataGetter: (node: PentestEntry) => node,
|
||||||
|
childrenGetter: (node: PentestEntry) => node.childEntries || undefined,
|
||||||
|
expandedGetter: (node: PentestEntry) => !!node.expanded,
|
||||||
|
};
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
private store: Store,
|
||||||
|
private pentestService: PentestService,
|
||||||
|
private dataSourceBuilder: NbTreeGridDataSourceBuilder<PentestEntry>
|
||||||
|
) {
|
||||||
|
this.dataSource = dataSourceBuilder.create(this.data, this.getters);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ngOnInit(): void {
|
||||||
|
this.loadPentestData();
|
||||||
|
}
|
||||||
|
|
||||||
|
loadPentestData(): void {
|
||||||
|
this.store.select(ProjectState.selectedCategory).pipe(
|
||||||
|
switchMap(category => this.pentestService.loadPentests(category)),
|
||||||
|
catchError(_ => of(null)),
|
||||||
|
untilDestroyed(this)
|
||||||
|
).subscribe({
|
||||||
|
next: (pentests: Pentest[]) => {
|
||||||
|
this.data = transformPentestsToEntries(pentests);
|
||||||
|
this.dataSource.setData(this.data, this.getters);
|
||||||
|
},
|
||||||
|
error: error => {
|
||||||
|
console.error(error);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// HTML only
|
||||||
|
getTitle(refNumber: string): string {
|
||||||
|
return getTitleKeyForRefNumber(refNumber);
|
||||||
|
}
|
||||||
|
|
||||||
|
ngOnDestroy(): void {
|
||||||
|
// This method must be present when using ngx-take-until-destroy
|
||||||
|
// even when empty
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
enum PentestColumns {
|
||||||
|
TEST_ID = 'testId',
|
||||||
|
TITLE = 'title',
|
||||||
|
STATUS = 'status',
|
||||||
|
FINDINGS = 'findings'
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,2 @@
|
||||||
|
export {PentestModule} from './pentest.module';
|
||||||
|
export {PentestRoutingModule} from './pentest-routing.module';
|
|
@ -0,0 +1,17 @@
|
||||||
|
import {NgModule} from '@angular/core';
|
||||||
|
import {RouterModule, Routes} from '@angular/router';
|
||||||
|
import {PentestComponent} from './pentest.component';
|
||||||
|
|
||||||
|
const routes: Routes = [
|
||||||
|
{
|
||||||
|
path: '',
|
||||||
|
component: PentestComponent
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
@NgModule({
|
||||||
|
imports: [RouterModule.forChild(routes)],
|
||||||
|
exports: [RouterModule]
|
||||||
|
})
|
||||||
|
export class PentestRoutingModule {
|
||||||
|
}
|
|
@ -0,0 +1,5 @@
|
||||||
|
<nb-layout>
|
||||||
|
<nb-layout-header>
|
||||||
|
<p>pentest works!</p>
|
||||||
|
</nb-layout-header>
|
||||||
|
</nb-layout>
|
|
@ -0,0 +1,35 @@
|
||||||
|
import {ComponentFixture, TestBed} from '@angular/core/testing';
|
||||||
|
|
||||||
|
import {PentestComponent} from './pentest.component';
|
||||||
|
import {NbLayoutModule} from '@nebular/theme';
|
||||||
|
import {ThemeModule} from '@assets/@theme/theme.module';
|
||||||
|
import {RouterTestingModule} from '@angular/router/testing';
|
||||||
|
|
||||||
|
describe('PentestComponent', () => {
|
||||||
|
let component: PentestComponent;
|
||||||
|
let fixture: ComponentFixture<PentestComponent>;
|
||||||
|
|
||||||
|
beforeEach(async () => {
|
||||||
|
await TestBed.configureTestingModule({
|
||||||
|
declarations: [
|
||||||
|
PentestComponent
|
||||||
|
],
|
||||||
|
imports: [
|
||||||
|
NbLayoutModule,
|
||||||
|
ThemeModule.forRoot(),
|
||||||
|
RouterTestingModule.withRoutes([])
|
||||||
|
]
|
||||||
|
})
|
||||||
|
.compileComponents();
|
||||||
|
});
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
fixture = TestBed.createComponent(PentestComponent);
|
||||||
|
component = fixture.componentInstance;
|
||||||
|
fixture.detectChanges();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should create', () => {
|
||||||
|
expect(component).toBeTruthy();
|
||||||
|
});
|
||||||
|
});
|
|
@ -0,0 +1,17 @@
|
||||||
|
import { Component, OnInit } from '@angular/core';
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'app-pentest',
|
||||||
|
templateUrl: './pentest.component.html',
|
||||||
|
styleUrls: ['./pentest.component.scss']
|
||||||
|
})
|
||||||
|
export class PentestComponent implements OnInit {
|
||||||
|
|
||||||
|
constructor() { }
|
||||||
|
|
||||||
|
ngOnInit(): void {
|
||||||
|
// tslint:disable-next-line:no-console
|
||||||
|
console.info('pentest component renderd');
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,21 @@
|
||||||
|
import {NgModule} from '@angular/core';
|
||||||
|
import {CommonModule} from '@angular/common';
|
||||||
|
import {RouterModule} from '@angular/router';
|
||||||
|
import {PentestComponent} from './pentest.component';
|
||||||
|
import {NbLayoutModule} from '@nebular/theme';
|
||||||
|
|
||||||
|
@NgModule({
|
||||||
|
declarations: [
|
||||||
|
PentestComponent
|
||||||
|
],
|
||||||
|
imports: [
|
||||||
|
CommonModule,
|
||||||
|
RouterModule.forChild([{
|
||||||
|
path: '',
|
||||||
|
component: PentestComponent
|
||||||
|
}]),
|
||||||
|
NbLayoutModule
|
||||||
|
]
|
||||||
|
})
|
||||||
|
export class PentestModule {
|
||||||
|
}
|
|
@ -10,7 +10,7 @@ const routes: Routes = [
|
||||||
{
|
{
|
||||||
path: 'id',
|
path: 'id',
|
||||||
loadChildren: () => import('./project').then(mod => mod.ProjectModule),
|
loadChildren: () => import('./project').then(mod => mod.ProjectModule),
|
||||||
},
|
}
|
||||||
];
|
];
|
||||||
|
|
||||||
@NgModule({
|
@NgModule({
|
||||||
|
|
|
@ -26,6 +26,7 @@ import {DialogService} from '@shared/services/dialog-service/dialog.service';
|
||||||
import {DialogServiceMock} from '@shared/services/dialog-service/dialog.service.mock';
|
import {DialogServiceMock} from '@shared/services/dialog-service/dialog.service.mock';
|
||||||
import {ProjectDialogService} from '@shared/modules/project-dialog/service/project-dialog.service';
|
import {ProjectDialogService} from '@shared/modules/project-dialog/service/project-dialog.service';
|
||||||
import {ProjectDialogServiceMock} from '@shared/modules/project-dialog/service/project-dialog.service.mock';
|
import {ProjectDialogServiceMock} from '@shared/modules/project-dialog/service/project-dialog.service.mock';
|
||||||
|
import {MockComponent, MockPipe} from 'ng-mocks';
|
||||||
|
|
||||||
describe('ProjectOverviewComponent', () => {
|
describe('ProjectOverviewComponent', () => {
|
||||||
let component: ProjectOverviewComponent;
|
let component: ProjectOverviewComponent;
|
||||||
|
@ -35,8 +36,8 @@ describe('ProjectOverviewComponent', () => {
|
||||||
await TestBed.configureTestingModule({
|
await TestBed.configureTestingModule({
|
||||||
declarations: [
|
declarations: [
|
||||||
ProjectOverviewComponent,
|
ProjectOverviewComponent,
|
||||||
LoadingSpinnerComponent,
|
MockComponent(LoadingSpinnerComponent),
|
||||||
DateTimeFormatPipe
|
MockPipe(DateTimeFormatPipe)
|
||||||
],
|
],
|
||||||
imports: [
|
imports: [
|
||||||
CommonModule,
|
CommonModule,
|
||||||
|
@ -49,6 +50,7 @@ describe('ProjectOverviewComponent', () => {
|
||||||
TranslateModule,
|
TranslateModule,
|
||||||
NbProgressBarModule,
|
NbProgressBarModule,
|
||||||
NbSpinnerModule,
|
NbSpinnerModule,
|
||||||
|
HttpClientTestingModule,
|
||||||
ThemeModule.forRoot(),
|
ThemeModule.forRoot(),
|
||||||
TranslateModule.forRoot({
|
TranslateModule.forRoot({
|
||||||
loader: {
|
loader: {
|
||||||
|
@ -58,9 +60,7 @@ describe('ProjectOverviewComponent', () => {
|
||||||
}
|
}
|
||||||
}),
|
}),
|
||||||
RouterTestingModule.withRoutes([]),
|
RouterTestingModule.withRoutes([]),
|
||||||
NgxsModule.forRoot([SessionState]),
|
NgxsModule.forRoot([SessionState])
|
||||||
HttpClientModule,
|
|
||||||
HttpClientTestingModule
|
|
||||||
],
|
],
|
||||||
providers: [
|
providers: [
|
||||||
KeycloakService,
|
KeycloakService,
|
||||||
|
|
|
@ -7,6 +7,10 @@ const routes: Routes = [
|
||||||
path: '',
|
path: '',
|
||||||
component: ProjectComponent
|
component: ProjectComponent
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
path: 'pentest',
|
||||||
|
loadChildren: () => import('../../pentest-overview/pentest').then(mod => mod.PentestModule),
|
||||||
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
@NgModule({
|
@NgModule({
|
||||||
|
|
|
@ -12,11 +12,12 @@
|
||||||
|
|
||||||
.categories-column {
|
.categories-column {
|
||||||
width: 20%;
|
width: 20%;
|
||||||
height: calc(100% - #{$pentest-header-height});
|
height: calc(100vh - #{$pentest-header-height});
|
||||||
}
|
}
|
||||||
|
|
||||||
.table-column {
|
.table-column {
|
||||||
|
overflow: auto !important;
|
||||||
width: 80%;
|
width: 80%;
|
||||||
height: calc(100% - #{$pentest-header-height});
|
height: 80vh;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,15 +1,42 @@
|
||||||
import { Component, OnInit } from '@angular/core';
|
import {Component, OnDestroy, OnInit} from '@angular/core';
|
||||||
|
import {Store} from '@ngxs/store';
|
||||||
|
import {InitProjectState} from '@shared/stores/project-state/project-state.actions';
|
||||||
|
import {Router} from '@angular/router';
|
||||||
|
import {Route} from '@shared/models/route.enum';
|
||||||
|
import {untilDestroyed} from 'ngx-take-until-destroy';
|
||||||
|
import {Project} from '@shared/models/project.model';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-project',
|
selector: 'app-project',
|
||||||
templateUrl: './project.component.html',
|
templateUrl: './project.component.html',
|
||||||
styleUrls: ['./project.component.scss']
|
styleUrls: ['./project.component.scss']
|
||||||
})
|
})
|
||||||
export class ProjectComponent implements OnInit {
|
export class ProjectComponent implements OnInit, OnDestroy {
|
||||||
|
|
||||||
constructor() { }
|
constructor(
|
||||||
|
private store: Store,
|
||||||
ngOnInit(): void {
|
private readonly router: Router) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ngOnInit(): void {
|
||||||
|
if (history?.state && 'selectedProject' in history?.state) {
|
||||||
|
this.initProjectStore();
|
||||||
|
} else {
|
||||||
|
this.router.navigate([Route.PROJECT_OVERVIEW]).finally();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private initProjectStore(): void {
|
||||||
|
const project: Project = history?.state?.selectedProject ? history?.state?.selectedProject : null;
|
||||||
|
this.store.dispatch(new InitProjectState(
|
||||||
|
project,
|
||||||
|
[],
|
||||||
|
[]
|
||||||
|
)).pipe(untilDestroyed(this)).subscribe();
|
||||||
|
}
|
||||||
|
|
||||||
|
ngOnDestroy(): void {
|
||||||
|
// This method must be present when using ngx-take-until-destroy
|
||||||
|
// even when empty
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,2 +1,2 @@
|
||||||
$header-height: 10rem;
|
$header-height: 8rem;
|
||||||
$pentest-header-height: 8rem;
|
$pentest-header-height: 8rem;
|
||||||
|
|
|
@ -69,5 +69,143 @@
|
||||||
"delete.success": "Projekt erfolgreich gelöscht",
|
"delete.success": "Projekt erfolgreich gelöscht",
|
||||||
"delete.failed": "Projekt konnte nicht gelöscht werden"
|
"delete.failed": "Projekt konnte nicht gelöscht werden"
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
"pentest": {
|
||||||
|
"testId": "Nr.",
|
||||||
|
"title": "Titel",
|
||||||
|
"findings": "Funde",
|
||||||
|
"comments": "Kommentare",
|
||||||
|
"status": "Status",
|
||||||
|
"statusText": {
|
||||||
|
"not_started": "Nicht angefangen",
|
||||||
|
"disabled": "Deaktiviert",
|
||||||
|
"open": "Offen",
|
||||||
|
"checked": "Geprüft",
|
||||||
|
"reported": "Gemeldet",
|
||||||
|
"under_review": "Unter Beurteilung",
|
||||||
|
"triaged": "Triagiert"
|
||||||
|
},
|
||||||
|
"info": {
|
||||||
|
"001": "Nutze Suchmaschinenerkennung und -aufklärung für Informationslecks",
|
||||||
|
"002": "Fingerabdruck-Webserver",
|
||||||
|
"003": "Prüfe Webserver-Metadateien auf Informationslecks",
|
||||||
|
"004": "Anwendungen auf dem Webserver auflisten",
|
||||||
|
"005": "Prüfe Webseitenkommentare und Metadaten auf Informationslecks",
|
||||||
|
"006": "Einstiegspunkte für Identitätsanträge",
|
||||||
|
"007": "Zuordnen von Ausführungspfade der Anwendung",
|
||||||
|
"008": "Framework für Fingerabdruck-Webanwendungen",
|
||||||
|
"009": "Fingerabdruck-Webanwendungen",
|
||||||
|
"010": "Zuordnen der Anwendungsarchitektur"
|
||||||
|
},
|
||||||
|
"config": {
|
||||||
|
"001": "Netzwerk-/Infrastrukturkonfiguration testen",
|
||||||
|
"002": "Testen Sie die Konfiguration der Anwendungsplattform",
|
||||||
|
"003": "Testen der Behandlung von Dateierweiterungen für vertrauliche Informationen",
|
||||||
|
"004": "Backup und nicht referenzierte Dateien für sensible Informationen",
|
||||||
|
"005": "Aufzählen der Infrastruktur- und Anwendungsverwaltungsschnittstellen",
|
||||||
|
"006": "HTTP-Methoden testen",
|
||||||
|
"007": "Testen Sie HTTP Strict Transport Security",
|
||||||
|
"008": "Testen der domänenübergreifende RIA-Richtlinie"
|
||||||
|
},
|
||||||
|
"ident": {
|
||||||
|
"001": "Rollendefinitionen testen",
|
||||||
|
"002": "Registrierungsprozess testen",
|
||||||
|
"003": "Konto-Bereitstellungsprozess testen",
|
||||||
|
"004": "Testen auf Kontoaufzählung und erratbares Benutzerkonto",
|
||||||
|
"005": "Test auf schwache oder nicht erzwungene Richtlinie für Benutzernamen",
|
||||||
|
"006": "Testberechtigungen von Gast-/Schulungskonten",
|
||||||
|
"007": "Sperrung/Wiederaufnahme des Kontos testen"
|
||||||
|
},
|
||||||
|
"authn": {
|
||||||
|
"001": "Testen auf Anmeldeinformationen, die über einen verschlüsselten Kanal transportiert werden",
|
||||||
|
"002": "Testen auf Standardanmeldeinformationen",
|
||||||
|
"003": "Test auf schwachen Sperrmechanismus",
|
||||||
|
"004": "Testen auf Umgehung des Authentifizierungsschemas",
|
||||||
|
"005": "Testen der Passwort speichern Funktion",
|
||||||
|
"006": "Test auf Browser-Cache-Schwäche",
|
||||||
|
"007": "Testen auf schwache Richtlinie für Kennwörter",
|
||||||
|
"008": "Prüfung auf schwache Sicherheitsfrage/Antwort",
|
||||||
|
"009": "Testen auf schwache Passwortänderungs- oder Zurücksetzungsfunktionen",
|
||||||
|
"010": "Testen auf schwächere Authentifizierung über alternativen Kanal"
|
||||||
|
},
|
||||||
|
"authz": {
|
||||||
|
"001": "Testen von Directory Traversal/File Include",
|
||||||
|
"002": "Testen auf Umgehung des Autorisierungsschemas",
|
||||||
|
"003": "Testen auf Rechteausweitung",
|
||||||
|
"004": "Testen auf unsichere direkte Objektreferenzen"
|
||||||
|
},
|
||||||
|
"sess": {
|
||||||
|
"001": "Testen auf Umgehung des Sitzungsverwaltungsschemas",
|
||||||
|
"002": "Testen auf Cookies-Attribute",
|
||||||
|
"003": "Testen auf Sitzungsfixierung",
|
||||||
|
"004": "Testen auf sichtbare Sitzungsvariablen",
|
||||||
|
"005": "Prüfung auf Cross-Site-Request-Forgery",
|
||||||
|
"006": "Testen der Abmeldefunktion",
|
||||||
|
"007": "Testen der Sitzungszeitüberschreitung",
|
||||||
|
"008": "Testen auf Session-Rätsel"
|
||||||
|
},
|
||||||
|
"inpval": {
|
||||||
|
"001": "Testen auf reflektiertes Cross-Site-Scripting",
|
||||||
|
"002": "Testen auf konserviertes Cross Site Scripting",
|
||||||
|
"003": "Testen auf HTTP-Verb-Manipulation",
|
||||||
|
"004": "Prüfung auf HTTP-Parameterverschmutzung",
|
||||||
|
"005": "N/A",
|
||||||
|
"006": "Testen auf SQL-Injection",
|
||||||
|
"006_1": "Oracle-Tests",
|
||||||
|
"006_2": "SQL Server-Tests",
|
||||||
|
"006_3": "Testen von PostgreSQL",
|
||||||
|
"006_4": "MS-Access-Tests",
|
||||||
|
"006_5": "Testen auf NoSQL-Injection",
|
||||||
|
"007": "Testen auf LDAP-Injection",
|
||||||
|
"008": "Prüfung auf ORM-Injection",
|
||||||
|
"009": "Testen auf XML-Injection",
|
||||||
|
"010": "Prüfung auf SSI-Injection",
|
||||||
|
"011": "Testen auf XPath-Injection",
|
||||||
|
"012": "IMAP/SMTP-Injection",
|
||||||
|
"013": "Testen auf Code-Injection",
|
||||||
|
"013_1": "Testen der lokalen Dateieinbindung",
|
||||||
|
"013_2": "Testen der Remote-Dateieinbindung",
|
||||||
|
"014": "Testen auf BefehlInjection",
|
||||||
|
"015": "Test auf Pufferüberlauf",
|
||||||
|
"015_1": "Test auf Heap-Überlauf",
|
||||||
|
"015_2": "Test auf Stack-Überlauf",
|
||||||
|
"015_3": "Testen auf Formatzeichenfolge",
|
||||||
|
"016": "Testen auf inkubierte Schwachstellen",
|
||||||
|
"017": "Testen auf HTTP-Splitting/-Schmuggel"
|
||||||
|
},
|
||||||
|
"err": {
|
||||||
|
"001": "Analyse von Fehlercodes",
|
||||||
|
"002": "Analyse von Stack-Traces"
|
||||||
|
},
|
||||||
|
"crypst": {
|
||||||
|
"001": "Testen auf schwache SSL/TSL-Chiffren, unzureichenden Transportschichtschutz",
|
||||||
|
"002": "Testen für Padding Oracle",
|
||||||
|
"003": "Prüfung auf sensible Informationen, die über unverschlüsselte Kanäle gesendet werden"
|
||||||
|
},
|
||||||
|
"buslogic": {
|
||||||
|
"001": "Testen Sie die Datenvalidierung der Geschäftslogik",
|
||||||
|
"002": "Testen Sie die Fähigkeit, Anfragen zu fälschen",
|
||||||
|
"003": "Integritätsprüfungen testen",
|
||||||
|
"004": "Testen Sie das Prozesstiming",
|
||||||
|
"005": "Testen Sie, wie oft eine Funktion verwendet werden kann",
|
||||||
|
"006": "Prüfung auf Umgehung von Arbeitsabläufen",
|
||||||
|
"007": "Testen Sie Abwehrmaßnahmen gegen Anwendungsmissbrauch",
|
||||||
|
"008": "Test-Upload von unerwarteten Dateitypen",
|
||||||
|
"009": "Test-Upload schädlicher Dateien"
|
||||||
|
},
|
||||||
|
"client": {
|
||||||
|
"001": "Testen auf DOM-basiertes Cross Site Scripting",
|
||||||
|
"002": "Testen auf JavaScript-Ausführung",
|
||||||
|
"003": "Testen auf HTML-Injection",
|
||||||
|
"004": "Testen der clientseitigen URL-Umleitung",
|
||||||
|
"005": "Testen auf CSS-Injektion",
|
||||||
|
"006": "Testen auf clientseitige Ressourcenmanipulation",
|
||||||
|
"007": "Testen Sie die ursprungsübergreifende Ressourcenfreigabe",
|
||||||
|
"008": "Testen auf Cross-Site-Flashing",
|
||||||
|
"009": "Test auf Clickjacking",
|
||||||
|
"010": "Testen von WebSockets",
|
||||||
|
"011": "Testen von Web-Messaging",
|
||||||
|
"012": "Lokalen Speicher testen"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -69,5 +69,143 @@
|
||||||
"delete.success": "Project deleted successfully",
|
"delete.success": "Project deleted successfully",
|
||||||
"delete.failed": "Project could not be deleted"
|
"delete.failed": "Project could not be deleted"
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
"pentest": {
|
||||||
|
"testId": "No.",
|
||||||
|
"title": "Title",
|
||||||
|
"findings": "Findings",
|
||||||
|
"comments": "Comments",
|
||||||
|
"status": "Status",
|
||||||
|
"statusText": {
|
||||||
|
"not_started": "Not Started",
|
||||||
|
"disabled": "Disabled",
|
||||||
|
"open": "Open",
|
||||||
|
"checked": "Checked",
|
||||||
|
"reported": "Reported",
|
||||||
|
"under_review": "Under Review",
|
||||||
|
"triaged": "Triaged"
|
||||||
|
},
|
||||||
|
"info": {
|
||||||
|
"001": "Conduct Search Engine Discovery and Reconnaissance for Information Leakage",
|
||||||
|
"002": "Fingerprint Web Server",
|
||||||
|
"003": "Review Webserver Metafiles for Information Leakage",
|
||||||
|
"004": "Enumerate Applications on Webserver",
|
||||||
|
"005": "Review Webpage Comments and Metadata for Information Leakage",
|
||||||
|
"006": "Identity application entry points",
|
||||||
|
"007": "Map execution paths through application",
|
||||||
|
"008": "Fingerprint Web Application Framework",
|
||||||
|
"009": "Fingerprint Web Application",
|
||||||
|
"010": "Map Application Architecture"
|
||||||
|
},
|
||||||
|
"config": {
|
||||||
|
"001": "Test Network/Infrastructure Configuration",
|
||||||
|
"002": "Test Application Platform Configuration",
|
||||||
|
"003": "Test File Extensions Handling for Sensitive Information",
|
||||||
|
"004": "Backup and Unreferenced Files for Sensitive Information",
|
||||||
|
"005": "Enumerate Infrastructure and Application Admin Interfaces",
|
||||||
|
"006": "Test HTTP Methods",
|
||||||
|
"007": "Test HTTP Strict Transport Security",
|
||||||
|
"008": "Test RIA cross domain policy"
|
||||||
|
},
|
||||||
|
"ident": {
|
||||||
|
"001": "Test Role Definitions",
|
||||||
|
"002": "Test User Registration Process",
|
||||||
|
"003": "Test Account Provisioning Process",
|
||||||
|
"004": "Testing for Account Enumeration and Guessable User Account",
|
||||||
|
"005": "Testing for Weak or unenforced username policy",
|
||||||
|
"006": "Test Permissions of Guest/Training Accounts",
|
||||||
|
"007": "Test Account Suspension/Resumption Process"
|
||||||
|
},
|
||||||
|
"authn": {
|
||||||
|
"001": "Testing for Credentials Transported over an Encrypted Channel",
|
||||||
|
"002": "Testing for default credentials",
|
||||||
|
"003": "Testing for Weak lock out mechanism",
|
||||||
|
"004": "Testing for bypassing authentication schema",
|
||||||
|
"005": "Test remember password functionality",
|
||||||
|
"006": "Testing for Browser cache weakness",
|
||||||
|
"007": "Testing for Weak password policy",
|
||||||
|
"008": "Testing for Weak security question/answer",
|
||||||
|
"009": "Testing for weak password change or reset functionalities",
|
||||||
|
"010": "Testing for Weaker authentication in alternative channel"
|
||||||
|
},
|
||||||
|
"authz": {
|
||||||
|
"001": "Testing Directory traversal/file include",
|
||||||
|
"002": "Testing for bypassing authorization schema",
|
||||||
|
"003": "Testing for Privilege Escalation",
|
||||||
|
"004": "Testing for Insecure Direct Object References"
|
||||||
|
},
|
||||||
|
"sess": {
|
||||||
|
"001": "Testing for Bypassing Session Management Schema",
|
||||||
|
"002": "Testing for Cookies attributes",
|
||||||
|
"003": "Testing for Session Fixation",
|
||||||
|
"004": "Testing for Exposed Session Variables",
|
||||||
|
"005": "Testing for Cross Site Request Forgery",
|
||||||
|
"006": "Testing for logout functionality",
|
||||||
|
"007": "Test Session Timeout",
|
||||||
|
"008": "Testing for Session puzzling"
|
||||||
|
},
|
||||||
|
"inpval": {
|
||||||
|
"001": "Testing for Reflected Cross Site Scripting",
|
||||||
|
"002": "Testing for Stored Cross Site Scripting",
|
||||||
|
"003": "Testing for HTTP Verb Tampering",
|
||||||
|
"004": "Testing for HTTP Parameter pollution",
|
||||||
|
"005": "N/A",
|
||||||
|
"006": "Testing for SQL Injection",
|
||||||
|
"006_1": "Oracle Testing",
|
||||||
|
"006_2": "SQL Server Testing",
|
||||||
|
"006_3": "Testing PostgreSQL",
|
||||||
|
"006_4": "MS Access Testing",
|
||||||
|
"006_5": "Testing for NoSQL Injection",
|
||||||
|
"007": "Testing for LDAP Injection",
|
||||||
|
"008": "Testing for ORM Injection",
|
||||||
|
"009": "Testing for XML Injection",
|
||||||
|
"010": "Testing for SSI Injection",
|
||||||
|
"011": "Testing for XPath Injection",
|
||||||
|
"012": "IMAP/SMTP Injection",
|
||||||
|
"013": "Testing for Code Injection",
|
||||||
|
"013_1": "Testing Local File Inclusion",
|
||||||
|
"013_2": "Testing Remote File Inclusion",
|
||||||
|
"014": "Testing for Command Injection",
|
||||||
|
"015": "Testing for Buffer overflow",
|
||||||
|
"015_1": "Testing for Heap overflow",
|
||||||
|
"015_2": "Testing for Stack overflow",
|
||||||
|
"015_3": "Testing for Format string",
|
||||||
|
"016": "Testing for incubated vulnerabilities",
|
||||||
|
"017": "Testing for HTTP Splitting/Smuggling"
|
||||||
|
},
|
||||||
|
"err": {
|
||||||
|
"001": "Analysis of Error Codes",
|
||||||
|
"002": "Analysis of Stack Traces"
|
||||||
|
},
|
||||||
|
"crypst": {
|
||||||
|
"001": "Testing for Weak SSL/TSL Ciphers, Insufficient Transport Layer Protection",
|
||||||
|
"002": "Testing for Padding Oracle",
|
||||||
|
"003": "Testing for Sensitive information sent via unencrypted channels"
|
||||||
|
},
|
||||||
|
"buslogic": {
|
||||||
|
"001": "Test Business Logic Data Validation",
|
||||||
|
"002": "Test Ability to Forge Requests",
|
||||||
|
"003": "Test Integrity Checks",
|
||||||
|
"004": "Test for Process Timing",
|
||||||
|
"005": "Test Number of Times a Function Can be Used Limits",
|
||||||
|
"006": "Testing for the Circumvention of Work Flows",
|
||||||
|
"007": "Test Defenses Against Application Mis-use",
|
||||||
|
"008": "Test Upload of Unexpected File Types",
|
||||||
|
"009": "Test Upload of Malicious Files"
|
||||||
|
},
|
||||||
|
"client": {
|
||||||
|
"001": "Testing for DOM based Cross Site Scripting",
|
||||||
|
"002": "Testing for JavaScript Execution",
|
||||||
|
"003": "Testing for HTML Injection",
|
||||||
|
"004": "Testing for Client Side URL Redirect",
|
||||||
|
"005": "Testing for CSS Injection",
|
||||||
|
"006": "Testing for Client Side Resource Manipulation",
|
||||||
|
"007": "Test Cross Origin Resource Sharing",
|
||||||
|
"008": "Testing for Cross Site Flashing",
|
||||||
|
"009": "Testing for Clickjacking",
|
||||||
|
"010": "Testing WebSockets",
|
||||||
|
"011": "Test Web Messaging",
|
||||||
|
"012": "Test Local Storage"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -22,4 +22,4 @@ export const environment = {
|
||||||
* This import should be commented out in production mode because it will have a negative impact
|
* This import should be commented out in production mode because it will have a negative impact
|
||||||
* on performance if an error is thrown.
|
* on performance if an error is thrown.
|
||||||
*/
|
*/
|
||||||
// import 'zone.js/dist/zone-error'; // Included with Angular CLI.
|
// import 'zone.js/plugins/zone-error'; // Included with Angular CLI.
|
||||||
|
|
|
@ -59,7 +59,7 @@ import '@angular/localize/init';
|
||||||
/***************************************************************************************************
|
/***************************************************************************************************
|
||||||
* Zone JS is required by default for Angular itself.
|
* Zone JS is required by default for Angular itself.
|
||||||
*/
|
*/
|
||||||
import 'zone.js/dist/zone'; // Included with Angular CLI.
|
import 'zone.js'; // Included with Angular CLI.
|
||||||
(window as any).global = window;
|
(window as any).global = window;
|
||||||
(window as any).process = {
|
(window as any).process = {
|
||||||
env: {DEBUG: undefined},
|
env: {DEBUG: undefined},
|
||||||
|
|
|
@ -0,0 +1,58 @@
|
||||||
|
import {Pentest} from '@shared/models/pentest.model';
|
||||||
|
import {Category} from '@shared/models/category.model';
|
||||||
|
import {Status} from '@shared/models/status.model';
|
||||||
|
|
||||||
|
export function getAUTHN_Pentests(): Pentest[] {
|
||||||
|
return [
|
||||||
|
{
|
||||||
|
category: Category.AUTHENTICATION_TESTING,
|
||||||
|
refNumber: 'OTG-AUTHN-001',
|
||||||
|
status: Status.NOT_STARTED
|
||||||
|
},
|
||||||
|
{
|
||||||
|
category: Category.AUTHENTICATION_TESTING,
|
||||||
|
refNumber: 'OTG-AUTHN-002',
|
||||||
|
status: Status.NOT_STARTED
|
||||||
|
},
|
||||||
|
{
|
||||||
|
category: Category.AUTHENTICATION_TESTING,
|
||||||
|
refNumber: 'OTG-AUTHN-003',
|
||||||
|
status: Status.NOT_STARTED
|
||||||
|
},
|
||||||
|
{
|
||||||
|
category: Category.AUTHENTICATION_TESTING,
|
||||||
|
refNumber: 'OTG-AUTHN-004',
|
||||||
|
status: Status.NOT_STARTED
|
||||||
|
},
|
||||||
|
{
|
||||||
|
category: Category.AUTHENTICATION_TESTING,
|
||||||
|
refNumber: 'OTG-AUTHN-005',
|
||||||
|
status: Status.NOT_STARTED
|
||||||
|
},
|
||||||
|
{
|
||||||
|
category: Category.AUTHENTICATION_TESTING,
|
||||||
|
refNumber: 'OTG-AUTHN-006',
|
||||||
|
status: Status.NOT_STARTED
|
||||||
|
},
|
||||||
|
{
|
||||||
|
category: Category.AUTHENTICATION_TESTING,
|
||||||
|
refNumber: 'OTG-AUTHN-007',
|
||||||
|
status: Status.NOT_STARTED
|
||||||
|
},
|
||||||
|
{
|
||||||
|
category: Category.AUTHENTICATION_TESTING,
|
||||||
|
refNumber: 'OTG-AUTHN-008',
|
||||||
|
status: Status.NOT_STARTED
|
||||||
|
},
|
||||||
|
{
|
||||||
|
category: Category.AUTHENTICATION_TESTING,
|
||||||
|
refNumber: 'OTG-AUTHN-009',
|
||||||
|
status: Status.NOT_STARTED
|
||||||
|
},
|
||||||
|
{
|
||||||
|
category: Category.AUTHENTICATION_TESTING,
|
||||||
|
refNumber: 'OTG-AUTHN-010',
|
||||||
|
status: Status.NOT_STARTED
|
||||||
|
}
|
||||||
|
];
|
||||||
|
}
|
|
@ -0,0 +1,28 @@
|
||||||
|
import {Pentest} from '@shared/models/pentest.model';
|
||||||
|
import {Category} from '@shared/models/category.model';
|
||||||
|
import {Status} from '@shared/models/status.model';
|
||||||
|
|
||||||
|
export function getAUTHZ_Pentests(): Pentest[] {
|
||||||
|
return [
|
||||||
|
{
|
||||||
|
category: Category.AUTHORIZATION_TESTING,
|
||||||
|
refNumber: 'OTG-AUTHZ-001',
|
||||||
|
status: Status.NOT_STARTED
|
||||||
|
},
|
||||||
|
{
|
||||||
|
category: Category.AUTHORIZATION_TESTING,
|
||||||
|
refNumber: 'OTG-AUTHZ-002',
|
||||||
|
status: Status.NOT_STARTED
|
||||||
|
},
|
||||||
|
{
|
||||||
|
category: Category.AUTHORIZATION_TESTING,
|
||||||
|
refNumber: 'OTG-AUTHZ-003',
|
||||||
|
status: Status.NOT_STARTED
|
||||||
|
},
|
||||||
|
{
|
||||||
|
category: Category.AUTHORIZATION_TESTING,
|
||||||
|
refNumber: 'OTG-AUTHZ-004',
|
||||||
|
status: Status.NOT_STARTED
|
||||||
|
}
|
||||||
|
];
|
||||||
|
}
|
|
@ -0,0 +1,53 @@
|
||||||
|
import {Pentest} from '@shared/models/pentest.model';
|
||||||
|
import {Category} from '@shared/models/category.model';
|
||||||
|
import {Status} from '@shared/models/status.model';
|
||||||
|
|
||||||
|
export function getBUSLOGIC_Pentests(): Pentest[] {
|
||||||
|
return [
|
||||||
|
{
|
||||||
|
category: Category.BUSINESS_LOGIC_TESTING,
|
||||||
|
refNumber: 'OTG-BUSLOGIC-001',
|
||||||
|
status: Status.NOT_STARTED
|
||||||
|
},
|
||||||
|
{
|
||||||
|
category: Category.BUSINESS_LOGIC_TESTING,
|
||||||
|
refNumber: 'OTG-BUSLOGIC-002',
|
||||||
|
status: Status.NOT_STARTED
|
||||||
|
},
|
||||||
|
{
|
||||||
|
category: Category.BUSINESS_LOGIC_TESTING,
|
||||||
|
refNumber: 'OTG-BUSLOGIC-003',
|
||||||
|
status: Status.NOT_STARTED
|
||||||
|
},
|
||||||
|
{
|
||||||
|
category: Category.BUSINESS_LOGIC_TESTING,
|
||||||
|
refNumber: 'OTG-BUSLOGIC-004',
|
||||||
|
status: Status.NOT_STARTED
|
||||||
|
},
|
||||||
|
{
|
||||||
|
category: Category.BUSINESS_LOGIC_TESTING,
|
||||||
|
refNumber: 'OTG-BUSLOGIC-005',
|
||||||
|
status: Status.NOT_STARTED
|
||||||
|
},
|
||||||
|
{
|
||||||
|
category: Category.BUSINESS_LOGIC_TESTING,
|
||||||
|
refNumber: 'OTG-BUSLOGIC-006',
|
||||||
|
status: Status.NOT_STARTED
|
||||||
|
},
|
||||||
|
{
|
||||||
|
category: Category.BUSINESS_LOGIC_TESTING,
|
||||||
|
refNumber: 'OTG-BUSLOGIC-007',
|
||||||
|
status: Status.NOT_STARTED
|
||||||
|
},
|
||||||
|
{
|
||||||
|
category: Category.BUSINESS_LOGIC_TESTING,
|
||||||
|
refNumber: 'OTG-BUSLOGIC-008',
|
||||||
|
status: Status.NOT_STARTED
|
||||||
|
},
|
||||||
|
{
|
||||||
|
category: Category.BUSINESS_LOGIC_TESTING,
|
||||||
|
refNumber: 'OTG-BUSLOGIC-009',
|
||||||
|
status: Status.NOT_STARTED
|
||||||
|
}
|
||||||
|
];
|
||||||
|
}
|
|
@ -0,0 +1,68 @@
|
||||||
|
import {Pentest} from '@shared/models/pentest.model';
|
||||||
|
import {Category} from '@shared/models/category.model';
|
||||||
|
import {Status} from '@shared/models/status.model';
|
||||||
|
|
||||||
|
export function getCLIENT_Pentests(): Pentest[] {
|
||||||
|
return [
|
||||||
|
{
|
||||||
|
category: Category.CLIENT_SIDE_TESTING,
|
||||||
|
refNumber: 'OTG-CLIENT-001',
|
||||||
|
status: Status.NOT_STARTED
|
||||||
|
},
|
||||||
|
{
|
||||||
|
category: Category.CLIENT_SIDE_TESTING,
|
||||||
|
refNumber: 'OTG-CLIENT-002',
|
||||||
|
status: Status.NOT_STARTED
|
||||||
|
},
|
||||||
|
{
|
||||||
|
category: Category.CLIENT_SIDE_TESTING,
|
||||||
|
refNumber: 'OTG-CLIENT-003',
|
||||||
|
status: Status.NOT_STARTED
|
||||||
|
},
|
||||||
|
{
|
||||||
|
category: Category.CLIENT_SIDE_TESTING,
|
||||||
|
refNumber: 'OTG-CLIENT-004',
|
||||||
|
status: Status.NOT_STARTED
|
||||||
|
},
|
||||||
|
{
|
||||||
|
category: Category.CLIENT_SIDE_TESTING,
|
||||||
|
refNumber: 'OTG-CLIENT-005',
|
||||||
|
status: Status.NOT_STARTED
|
||||||
|
},
|
||||||
|
{
|
||||||
|
category: Category.CLIENT_SIDE_TESTING,
|
||||||
|
refNumber: 'OTG-CLIENT-006',
|
||||||
|
status: Status.NOT_STARTED
|
||||||
|
},
|
||||||
|
{
|
||||||
|
category: Category.CLIENT_SIDE_TESTING,
|
||||||
|
refNumber: 'OTG-CLIENT-007',
|
||||||
|
status: Status.NOT_STARTED
|
||||||
|
},
|
||||||
|
{
|
||||||
|
category: Category.CLIENT_SIDE_TESTING,
|
||||||
|
refNumber: 'OTG-CLIENT-008',
|
||||||
|
status: Status.NOT_STARTED
|
||||||
|
},
|
||||||
|
{
|
||||||
|
category: Category.CLIENT_SIDE_TESTING,
|
||||||
|
refNumber: 'OTG-CLIENT-009',
|
||||||
|
status: Status.NOT_STARTED
|
||||||
|
},
|
||||||
|
{
|
||||||
|
category: Category.CLIENT_SIDE_TESTING,
|
||||||
|
refNumber: 'OTG-CLIENT-010',
|
||||||
|
status: Status.NOT_STARTED
|
||||||
|
},
|
||||||
|
{
|
||||||
|
category: Category.CLIENT_SIDE_TESTING,
|
||||||
|
refNumber: 'OTG-CLIENT-011',
|
||||||
|
status: Status.NOT_STARTED
|
||||||
|
},
|
||||||
|
{
|
||||||
|
category: Category.CLIENT_SIDE_TESTING,
|
||||||
|
refNumber: 'OTG-CLIENT-012',
|
||||||
|
status: Status.NOT_STARTED
|
||||||
|
}
|
||||||
|
];
|
||||||
|
}
|
|
@ -0,0 +1,48 @@
|
||||||
|
import {Pentest} from '@shared/models/pentest.model';
|
||||||
|
import {Category} from '@shared/models/category.model';
|
||||||
|
import {Status} from '@shared/models/status.model';
|
||||||
|
|
||||||
|
export function getCONFIG_Pentests(): Pentest[] {
|
||||||
|
return [
|
||||||
|
{
|
||||||
|
category: Category.CONFIGURATION_AND_DEPLOY_MANAGEMENT_TESTING,
|
||||||
|
refNumber: 'OTG-CONFIG-001',
|
||||||
|
status: Status.NOT_STARTED
|
||||||
|
},
|
||||||
|
{
|
||||||
|
category: Category.CONFIGURATION_AND_DEPLOY_MANAGEMENT_TESTING,
|
||||||
|
refNumber: 'OTG-CONFIG-002',
|
||||||
|
status: Status.NOT_STARTED
|
||||||
|
},
|
||||||
|
{
|
||||||
|
category: Category.CONFIGURATION_AND_DEPLOY_MANAGEMENT_TESTING,
|
||||||
|
refNumber: 'OTG-CONFIG-003',
|
||||||
|
status: Status.NOT_STARTED
|
||||||
|
},
|
||||||
|
{
|
||||||
|
category: Category.CONFIGURATION_AND_DEPLOY_MANAGEMENT_TESTING,
|
||||||
|
refNumber: 'OTG-CONFIG-004',
|
||||||
|
status: Status.NOT_STARTED
|
||||||
|
},
|
||||||
|
{
|
||||||
|
category: Category.CONFIGURATION_AND_DEPLOY_MANAGEMENT_TESTING,
|
||||||
|
refNumber: 'OTG-CONFIG-005',
|
||||||
|
status: Status.NOT_STARTED
|
||||||
|
},
|
||||||
|
{
|
||||||
|
category: Category.CONFIGURATION_AND_DEPLOY_MANAGEMENT_TESTING,
|
||||||
|
refNumber: 'OTG-CONFIG-006',
|
||||||
|
status: Status.NOT_STARTED
|
||||||
|
},
|
||||||
|
{
|
||||||
|
category: Category.CONFIGURATION_AND_DEPLOY_MANAGEMENT_TESTING,
|
||||||
|
refNumber: 'OTG-CONFIG-007',
|
||||||
|
status: Status.NOT_STARTED
|
||||||
|
},
|
||||||
|
{
|
||||||
|
category: Category.CONFIGURATION_AND_DEPLOY_MANAGEMENT_TESTING,
|
||||||
|
refNumber: 'OTG-CONFIG-008',
|
||||||
|
status: Status.NOT_STARTED
|
||||||
|
}
|
||||||
|
];
|
||||||
|
}
|
|
@ -0,0 +1,23 @@
|
||||||
|
import {Pentest} from '@shared/models/pentest.model';
|
||||||
|
import {Category} from '@shared/models/category.model';
|
||||||
|
import {Status} from '@shared/models/status.model';
|
||||||
|
|
||||||
|
export function getCRYPST_Pentests(): Pentest[] {
|
||||||
|
return [
|
||||||
|
{
|
||||||
|
category: Category.CRYPTOGRAPHY,
|
||||||
|
refNumber: 'OTG-CRYPST-001',
|
||||||
|
status: Status.NOT_STARTED
|
||||||
|
},
|
||||||
|
{
|
||||||
|
category: Category.CRYPTOGRAPHY,
|
||||||
|
refNumber: 'OTG-CRYPST-002',
|
||||||
|
status: Status.NOT_STARTED
|
||||||
|
},
|
||||||
|
{
|
||||||
|
category: Category.CRYPTOGRAPHY,
|
||||||
|
refNumber: 'OTG-CRYPST-003',
|
||||||
|
status: Status.NOT_STARTED
|
||||||
|
}
|
||||||
|
];
|
||||||
|
}
|
|
@ -0,0 +1,18 @@
|
||||||
|
import {Pentest} from '@shared/models/pentest.model';
|
||||||
|
import {Category} from '@shared/models/category.model';
|
||||||
|
import {Status} from '@shared/models/status.model';
|
||||||
|
|
||||||
|
export function getERR_Pentests(): Pentest[] {
|
||||||
|
return [
|
||||||
|
{
|
||||||
|
category: Category.ERROR_HANDLING,
|
||||||
|
refNumber: 'OTG-ERR-001',
|
||||||
|
status: Status.NOT_STARTED
|
||||||
|
},
|
||||||
|
{
|
||||||
|
category: Category.ERROR_HANDLING,
|
||||||
|
refNumber: 'OTG-ERR-002',
|
||||||
|
status: Status.NOT_STARTED
|
||||||
|
}
|
||||||
|
];
|
||||||
|
}
|
|
@ -0,0 +1,43 @@
|
||||||
|
import {Pentest} from '@shared/models/pentest.model';
|
||||||
|
import {Category} from '@shared/models/category.model';
|
||||||
|
import {Status} from '@shared/models/status.model';
|
||||||
|
|
||||||
|
export function getIDENT_Pentests(): Pentest[] {
|
||||||
|
return [
|
||||||
|
{
|
||||||
|
category: Category.IDENTITY_MANAGEMENT_TESTING,
|
||||||
|
refNumber: 'OTG-IDENT-001',
|
||||||
|
status: Status.NOT_STARTED
|
||||||
|
},
|
||||||
|
{
|
||||||
|
category: Category.IDENTITY_MANAGEMENT_TESTING,
|
||||||
|
refNumber: 'OTG-IDENT-002',
|
||||||
|
status: Status.NOT_STARTED
|
||||||
|
},
|
||||||
|
{
|
||||||
|
category: Category.IDENTITY_MANAGEMENT_TESTING,
|
||||||
|
refNumber: 'OTG-IDENT-003',
|
||||||
|
status: Status.NOT_STARTED
|
||||||
|
},
|
||||||
|
{
|
||||||
|
category: Category.IDENTITY_MANAGEMENT_TESTING,
|
||||||
|
refNumber: 'OTG-IDENT-004',
|
||||||
|
status: Status.NOT_STARTED
|
||||||
|
},
|
||||||
|
{
|
||||||
|
category: Category.IDENTITY_MANAGEMENT_TESTING,
|
||||||
|
refNumber: 'OTG-IDENT-005',
|
||||||
|
status: Status.NOT_STARTED
|
||||||
|
},
|
||||||
|
{
|
||||||
|
category: Category.IDENTITY_MANAGEMENT_TESTING,
|
||||||
|
refNumber: 'OTG-IDENT-006',
|
||||||
|
status: Status.NOT_STARTED
|
||||||
|
},
|
||||||
|
{
|
||||||
|
category: Category.IDENTITY_MANAGEMENT_TESTING,
|
||||||
|
refNumber: 'OTG-IDENT-007',
|
||||||
|
status: Status.NOT_STARTED
|
||||||
|
}
|
||||||
|
];
|
||||||
|
}
|
|
@ -0,0 +1,58 @@
|
||||||
|
import {Pentest} from '@shared/models/pentest.model';
|
||||||
|
import {Status} from '@shared/models/status.model';
|
||||||
|
import {Category} from '@shared/models/category.model';
|
||||||
|
|
||||||
|
export function getINFO_Pentests(): Pentest[] {
|
||||||
|
return [
|
||||||
|
{
|
||||||
|
category: Category.INFORMATION_GATHERING,
|
||||||
|
refNumber: 'OTG-INFO-001',
|
||||||
|
status: Status.NOT_STARTED
|
||||||
|
},
|
||||||
|
{
|
||||||
|
category: Category.INFORMATION_GATHERING,
|
||||||
|
refNumber: 'OTG-INFO-002',
|
||||||
|
status: Status.NOT_STARTED
|
||||||
|
},
|
||||||
|
{
|
||||||
|
category: Category.INFORMATION_GATHERING,
|
||||||
|
refNumber: 'OTG-INFO-003',
|
||||||
|
status: Status.NOT_STARTED
|
||||||
|
},
|
||||||
|
{
|
||||||
|
category: Category.INFORMATION_GATHERING,
|
||||||
|
refNumber: 'OTG-INFO-004',
|
||||||
|
status: Status.NOT_STARTED,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
category: Category.INFORMATION_GATHERING,
|
||||||
|
refNumber: 'OTG-INFO-005',
|
||||||
|
status: Status.NOT_STARTED,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
category: Category.INFORMATION_GATHERING,
|
||||||
|
refNumber: 'OTG-INFO-006',
|
||||||
|
status: Status.NOT_STARTED,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
category: Category.INFORMATION_GATHERING,
|
||||||
|
refNumber: 'OTG-INFO-007',
|
||||||
|
status: Status.NOT_STARTED,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
category: Category.INFORMATION_GATHERING,
|
||||||
|
refNumber: 'OTG-INFO-008',
|
||||||
|
status: Status.NOT_STARTED,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
category: Category.INFORMATION_GATHERING,
|
||||||
|
refNumber: 'OTG-INFO-009',
|
||||||
|
status: Status.NOT_STARTED,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
category: Category.INFORMATION_GATHERING,
|
||||||
|
refNumber: 'OTG-INFO-010',
|
||||||
|
status: Status.NOT_STARTED,
|
||||||
|
}
|
||||||
|
];
|
||||||
|
}
|
|
@ -0,0 +1,149 @@
|
||||||
|
import {Pentest} from '@shared/models/pentest.model';
|
||||||
|
import {Category} from '@shared/models/category.model';
|
||||||
|
import {Status} from '@shared/models/status.model';
|
||||||
|
|
||||||
|
export function getINPVAL_Pentests(): Pentest[] {
|
||||||
|
return [
|
||||||
|
{
|
||||||
|
category: Category.INPUT_VALIDATION_TESTING,
|
||||||
|
refNumber: 'OTG-INPVAL-001',
|
||||||
|
status: Status.NOT_STARTED
|
||||||
|
},
|
||||||
|
{
|
||||||
|
category: Category.INPUT_VALIDATION_TESTING,
|
||||||
|
refNumber: 'OTG-INPVAL-002',
|
||||||
|
status: Status.NOT_STARTED
|
||||||
|
},
|
||||||
|
{
|
||||||
|
category: Category.INPUT_VALIDATION_TESTING,
|
||||||
|
refNumber: 'OTG-INPVAL-003',
|
||||||
|
status: Status.NOT_STARTED
|
||||||
|
},
|
||||||
|
{
|
||||||
|
category: Category.INPUT_VALIDATION_TESTING,
|
||||||
|
refNumber: 'OTG-INPVAL-004',
|
||||||
|
status: Status.NOT_STARTED
|
||||||
|
},
|
||||||
|
{
|
||||||
|
category: Category.INPUT_VALIDATION_TESTING,
|
||||||
|
refNumber: 'OTG-INPVAL-005',
|
||||||
|
status: Status.NOT_STARTED
|
||||||
|
},
|
||||||
|
{
|
||||||
|
category: Category.INPUT_VALIDATION_TESTING,
|
||||||
|
refNumber: 'OTG-INPVAL-006',
|
||||||
|
status: Status.NOT_STARTED,
|
||||||
|
childEntries: [
|
||||||
|
{
|
||||||
|
category: Category.INPUT_VALIDATION_TESTING,
|
||||||
|
refNumber: 'OTG-INPVAL-006_1',
|
||||||
|
status: Status.NOT_STARTED
|
||||||
|
},
|
||||||
|
{
|
||||||
|
category: Category.INPUT_VALIDATION_TESTING,
|
||||||
|
refNumber: 'OTG-INPVAL-006_2',
|
||||||
|
status: Status.NOT_STARTED
|
||||||
|
},
|
||||||
|
{
|
||||||
|
category: Category.INPUT_VALIDATION_TESTING,
|
||||||
|
refNumber: 'OTG-INPVAL-006_3',
|
||||||
|
status: Status.NOT_STARTED
|
||||||
|
},
|
||||||
|
{
|
||||||
|
category: Category.INPUT_VALIDATION_TESTING,
|
||||||
|
refNumber: 'OTG-INPVAL-006_4',
|
||||||
|
status: Status.NOT_STARTED
|
||||||
|
},
|
||||||
|
{
|
||||||
|
category: Category.INPUT_VALIDATION_TESTING,
|
||||||
|
refNumber: 'OTG-INPVAL-006_5',
|
||||||
|
status: Status.NOT_STARTED
|
||||||
|
},
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
category: Category.INPUT_VALIDATION_TESTING,
|
||||||
|
refNumber: 'OTG-INPVAL-007',
|
||||||
|
status: Status.NOT_STARTED
|
||||||
|
},
|
||||||
|
{
|
||||||
|
category: Category.INPUT_VALIDATION_TESTING,
|
||||||
|
refNumber: 'OTG-INPVAL-008',
|
||||||
|
status: Status.NOT_STARTED
|
||||||
|
},
|
||||||
|
{
|
||||||
|
category: Category.INPUT_VALIDATION_TESTING,
|
||||||
|
refNumber: 'OTG-INPVAL-009',
|
||||||
|
status: Status.NOT_STARTED
|
||||||
|
},
|
||||||
|
{
|
||||||
|
category: Category.INPUT_VALIDATION_TESTING,
|
||||||
|
refNumber: 'OTG-INPVAL-010',
|
||||||
|
status: Status.NOT_STARTED
|
||||||
|
},
|
||||||
|
{
|
||||||
|
category: Category.INPUT_VALIDATION_TESTING,
|
||||||
|
refNumber: 'OTG-INPVAL-011',
|
||||||
|
status: Status.NOT_STARTED
|
||||||
|
},
|
||||||
|
{
|
||||||
|
category: Category.INPUT_VALIDATION_TESTING,
|
||||||
|
refNumber: 'OTG-INPVAL-012',
|
||||||
|
status: Status.NOT_STARTED
|
||||||
|
},
|
||||||
|
{
|
||||||
|
category: Category.INPUT_VALIDATION_TESTING,
|
||||||
|
refNumber: 'OTG-INPVAL-013',
|
||||||
|
status: Status.NOT_STARTED,
|
||||||
|
childEntries: [
|
||||||
|
{
|
||||||
|
category: Category.INPUT_VALIDATION_TESTING,
|
||||||
|
refNumber: 'OTG-INPVAL-013_1',
|
||||||
|
status: Status.NOT_STARTED
|
||||||
|
},
|
||||||
|
{
|
||||||
|
category: Category.INPUT_VALIDATION_TESTING,
|
||||||
|
refNumber: 'OTG-INPVAL-013_2',
|
||||||
|
status: Status.NOT_STARTED
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
category: Category.INPUT_VALIDATION_TESTING,
|
||||||
|
refNumber: 'OTG-INPVAL-014',
|
||||||
|
status: Status.NOT_STARTED
|
||||||
|
},
|
||||||
|
{
|
||||||
|
category: Category.INPUT_VALIDATION_TESTING,
|
||||||
|
refNumber: 'OTG-INPVAL-015',
|
||||||
|
status: Status.NOT_STARTED,
|
||||||
|
childEntries: [
|
||||||
|
{
|
||||||
|
category: Category.INPUT_VALIDATION_TESTING,
|
||||||
|
refNumber: 'OTG-INPVAL-015_1',
|
||||||
|
status: Status.NOT_STARTED
|
||||||
|
},
|
||||||
|
{
|
||||||
|
category: Category.INPUT_VALIDATION_TESTING,
|
||||||
|
refNumber: 'OTG-INPVAL-015_2',
|
||||||
|
status: Status.NOT_STARTED
|
||||||
|
},
|
||||||
|
{
|
||||||
|
category: Category.INPUT_VALIDATION_TESTING,
|
||||||
|
refNumber: 'OTG-INPVAL-015_3',
|
||||||
|
status: Status.NOT_STARTED
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
category: Category.INPUT_VALIDATION_TESTING,
|
||||||
|
refNumber: 'OTG-INPVAL-016',
|
||||||
|
status: Status.NOT_STARTED
|
||||||
|
},
|
||||||
|
{
|
||||||
|
category: Category.INPUT_VALIDATION_TESTING,
|
||||||
|
refNumber: 'OTG-INPVAL-017',
|
||||||
|
status: Status.NOT_STARTED
|
||||||
|
},
|
||||||
|
];
|
||||||
|
}
|
|
@ -0,0 +1,48 @@
|
||||||
|
import {Pentest} from '@shared/models/pentest.model';
|
||||||
|
import {Category} from '@shared/models/category.model';
|
||||||
|
import {Status} from '@shared/models/status.model';
|
||||||
|
|
||||||
|
export function getSESS_Pentests(): Pentest[] {
|
||||||
|
return [
|
||||||
|
{
|
||||||
|
category: Category.SESSION_MANAGEMENT_TESTING,
|
||||||
|
refNumber: 'OTG-SESS-001',
|
||||||
|
status: Status.NOT_STARTED
|
||||||
|
},
|
||||||
|
{
|
||||||
|
category: Category.SESSION_MANAGEMENT_TESTING,
|
||||||
|
refNumber: 'OTG-SESS-002',
|
||||||
|
status: Status.NOT_STARTED
|
||||||
|
},
|
||||||
|
{
|
||||||
|
category: Category.SESSION_MANAGEMENT_TESTING,
|
||||||
|
refNumber: 'OTG-SESS-003',
|
||||||
|
status: Status.NOT_STARTED
|
||||||
|
},
|
||||||
|
{
|
||||||
|
category: Category.SESSION_MANAGEMENT_TESTING,
|
||||||
|
refNumber: 'OTG-SESS-004',
|
||||||
|
status: Status.NOT_STARTED
|
||||||
|
},
|
||||||
|
{
|
||||||
|
category: Category.SESSION_MANAGEMENT_TESTING,
|
||||||
|
refNumber: 'OTG-SESS-005',
|
||||||
|
status: Status.NOT_STARTED
|
||||||
|
},
|
||||||
|
{
|
||||||
|
category: Category.SESSION_MANAGEMENT_TESTING,
|
||||||
|
refNumber: 'OTG-SESS-006',
|
||||||
|
status: Status.NOT_STARTED
|
||||||
|
},
|
||||||
|
{
|
||||||
|
category: Category.SESSION_MANAGEMENT_TESTING,
|
||||||
|
refNumber: 'OTG-SESS-007',
|
||||||
|
status: Status.NOT_STARTED
|
||||||
|
},
|
||||||
|
{
|
||||||
|
category: Category.SESSION_MANAGEMENT_TESTING,
|
||||||
|
refNumber: 'OTG-SESS-008',
|
||||||
|
status: Status.NOT_STARTED
|
||||||
|
}
|
||||||
|
];
|
||||||
|
}
|
|
@ -0,0 +1,70 @@
|
||||||
|
import {Category} from '@shared/models/category.model';
|
||||||
|
import {Pentest} from '@shared/models/pentest.model';
|
||||||
|
|
||||||
|
import {getINFO_Pentests} from '@shared/functions/categories/INFO/pentests.function';
|
||||||
|
import {getCONFIG_Pentests} from '@shared/functions/categories/CONFIG/pentests.function';
|
||||||
|
import {getIDENT_Pentests} from '@shared/functions/categories/IDENT/pentests.function';
|
||||||
|
import {getAUTHN_Pentests} from '@shared/functions/categories/AUTHN/pentests.function';
|
||||||
|
import {getAUTHZ_Pentests} from '@shared/functions/categories/AUTHZ/pentests.function';
|
||||||
|
import {getSESS_Pentests} from '@shared/functions/categories/SESS/pentests.function';
|
||||||
|
import {getINPVAL_Pentests} from '@shared/functions/categories/INPVAL/pentests.function';
|
||||||
|
import {getERR_Pentests} from '@shared/functions/categories/ERR/pentests.function';
|
||||||
|
import {getCRYPST_Pentests} from '@shared/functions/categories/CRYPST/pentests.function';
|
||||||
|
import {getBUSLOGIC_Pentests} from '@shared/functions/categories/BUSLOGIC/pentests.function';
|
||||||
|
import {getCLIENT_Pentests} from '@shared/functions/categories/CLIENT/pentests.function';
|
||||||
|
|
||||||
|
export function getTempPentestsForCategory(requestedCategory: Category): Pentest[] {
|
||||||
|
let pentests: Pentest[];
|
||||||
|
switch (requestedCategory) {
|
||||||
|
case Category.INFORMATION_GATHERING: {
|
||||||
|
pentests = getINFO_Pentests();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case Category.CONFIGURATION_AND_DEPLOY_MANAGEMENT_TESTING: {
|
||||||
|
pentests = getCONFIG_Pentests();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case Category.IDENTITY_MANAGEMENT_TESTING: {
|
||||||
|
pentests = getIDENT_Pentests();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case Category.AUTHENTICATION_TESTING: {
|
||||||
|
pentests = getAUTHN_Pentests();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case Category.AUTHORIZATION_TESTING: {
|
||||||
|
pentests = getAUTHZ_Pentests();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case Category.SESSION_MANAGEMENT_TESTING: {
|
||||||
|
pentests = getSESS_Pentests();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case Category.INPUT_VALIDATION_TESTING: {
|
||||||
|
pentests = getINPVAL_Pentests();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case Category.ERROR_HANDLING: {
|
||||||
|
pentests = getERR_Pentests();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case Category.CRYPTOGRAPHY: {
|
||||||
|
pentests = getCRYPST_Pentests();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case Category.BUSINESS_LOGIC_TESTING: {
|
||||||
|
pentests = getBUSLOGIC_Pentests();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case Category.CLIENT_SIDE_TESTING: {
|
||||||
|
pentests = getCLIENT_Pentests();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default: {
|
||||||
|
pentests = [];
|
||||||
|
console.error('Invalid categories: ', requestedCategory);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return pentests;
|
||||||
|
}
|
|
@ -0,0 +1,63 @@
|
||||||
|
export function getTitleKeyForRefNumber(refNumber: string): string {
|
||||||
|
let translationKey = 'pentest.';
|
||||||
|
let subRefNumberKey;
|
||||||
|
const refNumberKey = refNumber.slice(refNumber.length - 3);
|
||||||
|
|
||||||
|
switch (true) {
|
||||||
|
case refNumber.includes('INFO'): {
|
||||||
|
translationKey += 'info.' + refNumberKey;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case refNumber.includes('CONFIG'): {
|
||||||
|
translationKey += 'config.' + refNumberKey;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case refNumber.includes('IDENT'): {
|
||||||
|
translationKey += 'ident.' + refNumberKey;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case refNumber.includes('AUTHN'): {
|
||||||
|
translationKey += 'authn.' + refNumberKey;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case refNumber.includes('AUTHZ'): {
|
||||||
|
translationKey += 'authz.' + refNumberKey;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case refNumber.includes('SESS'): {
|
||||||
|
translationKey += 'sess.' + refNumberKey;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case refNumber.includes('INPVAL'): {
|
||||||
|
if (refNumber.includes('_')) {
|
||||||
|
subRefNumberKey = refNumber.slice(refNumber.length - 5);
|
||||||
|
translationKey += 'inpval.' + subRefNumberKey;
|
||||||
|
} else {
|
||||||
|
translationKey += 'inpval.' + refNumberKey;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case refNumber.includes('ERR'): {
|
||||||
|
translationKey += 'err.' + refNumberKey;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case refNumber.includes('CRYPST'): {
|
||||||
|
translationKey += 'crypst.' + refNumberKey;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case refNumber.includes('BUSLOGIC'): {
|
||||||
|
translationKey += 'buslogic.' + refNumberKey;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case refNumber.includes('CLIENT'): {
|
||||||
|
translationKey += 'client.' + refNumberKey;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default: {
|
||||||
|
translationKey = 'pentest.categories.translation';
|
||||||
|
console.error('Invalid category number: ', refNumber.slice(4 - refNumber.length));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return translationKey;
|
||||||
|
}
|
|
@ -0,0 +1,20 @@
|
||||||
|
export enum Category {
|
||||||
|
INFORMATION_GATHERING,
|
||||||
|
CONFIGURATION_AND_DEPLOY_MANAGEMENT_TESTING,
|
||||||
|
IDENTITY_MANAGEMENT_TESTING,
|
||||||
|
AUTHENTICATION_TESTING,
|
||||||
|
AUTHORIZATION_TESTING,
|
||||||
|
SESSION_MANAGEMENT_TESTING,
|
||||||
|
INPUT_VALIDATION_TESTING,
|
||||||
|
ERROR_HANDLING,
|
||||||
|
CRYPTOGRAPHY,
|
||||||
|
BUSINESS_LOGIC_TESTING,
|
||||||
|
CLIENT_SIDE_TESTING
|
||||||
|
}
|
||||||
|
|
||||||
|
export class CategoryDetails {
|
||||||
|
id: string;
|
||||||
|
name: Category;
|
||||||
|
disabledPentests: Array<string>;
|
||||||
|
disabled: false;
|
||||||
|
}
|
|
@ -0,0 +1,51 @@
|
||||||
|
import {v4 as UUID} from 'uuid';
|
||||||
|
import {Status} from '@shared/models/status.model';
|
||||||
|
import {Category} from '@shared/models/category.model';
|
||||||
|
|
||||||
|
export class Pentest {
|
||||||
|
id?: string;
|
||||||
|
category: Category;
|
||||||
|
refNumber: string;
|
||||||
|
childEntries?: Pentest[];
|
||||||
|
status: Status;
|
||||||
|
findingsIds?: Array<string>;
|
||||||
|
commentsIds?: Array<string>;
|
||||||
|
|
||||||
|
constructor(category: Category,
|
||||||
|
refNumber: string,
|
||||||
|
status: Status,
|
||||||
|
id?: string,
|
||||||
|
findingsIds?: Array<string>,
|
||||||
|
commentsIds?: Array<string>) {
|
||||||
|
this.id = id ? id : UUID();
|
||||||
|
this.category = category;
|
||||||
|
this.refNumber = refNumber;
|
||||||
|
this.status = status;
|
||||||
|
this.findingsIds = findingsIds ? findingsIds : [];
|
||||||
|
this.commentsIds = commentsIds ? commentsIds : [];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface PentestEntry {
|
||||||
|
refNumber: string;
|
||||||
|
status: string;
|
||||||
|
findings?: number;
|
||||||
|
kind?: string;
|
||||||
|
childEntries?: PentestEntry[];
|
||||||
|
expanded?: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function transformPentestsToEntries(pentests: Pentest[]): PentestEntry[] {
|
||||||
|
const pentestEntries: PentestEntry[] = [];
|
||||||
|
pentests.forEach((value: Pentest) => {
|
||||||
|
pentestEntries.push({
|
||||||
|
refNumber: value.refNumber,
|
||||||
|
status: value.status,
|
||||||
|
findings: value.findingsIds ? value.findingsIds.length : 0,
|
||||||
|
kind: value.childEntries ? 'dir' : 'cell',
|
||||||
|
childEntries: value.childEntries ? value.childEntries : null,
|
||||||
|
expanded: !!value.childEntries
|
||||||
|
} as PentestEntry);
|
||||||
|
});
|
||||||
|
return pentestEntries;
|
||||||
|
}
|
|
@ -0,0 +1,4 @@
|
||||||
|
export enum Route {
|
||||||
|
HOME = 'home',
|
||||||
|
PROJECT_OVERVIEW = 'projects'
|
||||||
|
}
|
|
@ -0,0 +1,9 @@
|
||||||
|
export enum Status {
|
||||||
|
NOT_STARTED = 'NOT_STARTED',
|
||||||
|
DISABLED = 'DISABLED',
|
||||||
|
OPEN = 'OPEN',
|
||||||
|
CHECKED = 'CHECKED',
|
||||||
|
REPORTED = 'REPORTED',
|
||||||
|
UNDER_REVIEW = 'UNDER_REVIEW',
|
||||||
|
TRIAGED = 'TRIAGED'
|
||||||
|
}
|
|
@ -3,13 +3,14 @@ import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||||
import { ConfirmDialogComponent } from './confirm-dialog.component';
|
import { ConfirmDialogComponent } from './confirm-dialog.component';
|
||||||
import {DialogService} from '@shared/services/dialog-service/dialog.service';
|
import {DialogService} from '@shared/services/dialog-service/dialog.service';
|
||||||
import {DialogServiceMock} from '@shared/services/dialog-service/dialog.service.mock';
|
import {DialogServiceMock} from '@shared/services/dialog-service/dialog.service.mock';
|
||||||
import {NbButtonModule, NbCardModule, NbDialogRef, NbLayoutModule} from '@nebular/theme';
|
import {NbButtonModule, NbCardModule, NbDialogRef, NbLayoutModule, NbStatusService} from '@nebular/theme';
|
||||||
import {CommonModule} from '@angular/common';
|
import {CommonModule} from '@angular/common';
|
||||||
import {TranslateLoader, TranslateModule} from '@ngx-translate/core';
|
import {TranslateLoader, TranslateModule} from '@ngx-translate/core';
|
||||||
import {HttpLoaderFactory} from '../../../app/common-app.module';
|
import {HttpLoaderFactory} from '../../../app/common-app.module';
|
||||||
import {HttpClient, HttpClientModule} from '@angular/common/http';
|
import {HttpClient, HttpClientModule} from '@angular/common/http';
|
||||||
import {HttpClientTestingModule} from '@angular/common/http/testing';
|
import {HttpClientTestingModule} from '@angular/common/http/testing';
|
||||||
import {FlexLayoutModule} from '@angular/flex-layout';
|
import {FlexLayoutModule} from '@angular/flex-layout';
|
||||||
|
import {MockProvider} from 'ng-mocks';
|
||||||
|
|
||||||
describe('ConfirmDialogComponent', () => {
|
describe('ConfirmDialogComponent', () => {
|
||||||
let component: ConfirmDialogComponent;
|
let component: ConfirmDialogComponent;
|
||||||
|
@ -37,6 +38,7 @@ describe('ConfirmDialogComponent', () => {
|
||||||
HttpClientTestingModule
|
HttpClientTestingModule
|
||||||
],
|
],
|
||||||
providers: [
|
providers: [
|
||||||
|
MockProvider(NbStatusService),
|
||||||
{provide: DialogService, useClass: DialogServiceMock},
|
{provide: DialogService, useClass: DialogServiceMock},
|
||||||
{provide: NbDialogRef, useValue: {}}
|
{provide: NbDialogRef, useValue: {}}
|
||||||
]
|
]
|
||||||
|
|
|
@ -0,0 +1,26 @@
|
||||||
|
import { TestBed } from '@angular/core/testing';
|
||||||
|
|
||||||
|
import { PentestService } from './pentest.service';
|
||||||
|
import {HttpClientTestingModule} from '@angular/common/http/testing';
|
||||||
|
import {BrowserAnimationsModule} from '@angular/platform-browser/animations';
|
||||||
|
import {NgxsModule} from '@ngxs/store';
|
||||||
|
import {ProjectState} from '@shared/stores/project-state/project-state';
|
||||||
|
|
||||||
|
describe('PentestService', () => {
|
||||||
|
let service: PentestService;
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
TestBed.configureTestingModule({
|
||||||
|
imports: [
|
||||||
|
HttpClientTestingModule,
|
||||||
|
BrowserAnimationsModule,
|
||||||
|
NgxsModule.forRoot([ProjectState])
|
||||||
|
]
|
||||||
|
});
|
||||||
|
service = TestBed.inject(PentestService);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should be created', () => {
|
||||||
|
expect(service).toBeTruthy();
|
||||||
|
});
|
||||||
|
});
|
|
@ -0,0 +1,52 @@
|
||||||
|
import {Injectable} from '@angular/core';
|
||||||
|
import {environment} from '../../environments/environment';
|
||||||
|
import {HttpClient} from '@angular/common/http';
|
||||||
|
import {Observable, of} from 'rxjs';
|
||||||
|
import {Category} from '@shared/models/category.model';
|
||||||
|
import {Pentest} from '@shared/models/pentest.model';
|
||||||
|
import {Store} from '@ngxs/store';
|
||||||
|
import {ProjectState} from '@shared/stores/project-state/project-state';
|
||||||
|
import {catchError, map, switchMap} from 'rxjs/operators';
|
||||||
|
import {getTempPentestsForCategory} from '@shared/functions/categories/get-temp-pentests-for-category.function';
|
||||||
|
|
||||||
|
@Injectable({
|
||||||
|
providedIn: 'root'
|
||||||
|
})
|
||||||
|
export class PentestService {
|
||||||
|
|
||||||
|
private apiBaseURL = `${environment.apiEndpoint}/pentests`;
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
private http: HttpClient,
|
||||||
|
private readonly store: Store) {
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Load Pentests
|
||||||
|
* @param category the categories of which the pentests should be requested
|
||||||
|
*/
|
||||||
|
public loadPentests(category: Category): Observable<Pentest[]> {
|
||||||
|
return this.store.selectOnce(ProjectState.project).pipe(
|
||||||
|
switchMap(project => this.getPentestByProjectIdAndCategory(project.id, category)),
|
||||||
|
catchError(_ => of(null)),
|
||||||
|
map(response => {
|
||||||
|
let pentests = response;
|
||||||
|
if (!pentests) {
|
||||||
|
pentests = getTempPentestsForCategory(category);
|
||||||
|
// tslint:disable-next-line:no-console
|
||||||
|
console.info('Initial pentest data loaded.');
|
||||||
|
}
|
||||||
|
return pentests;
|
||||||
|
})
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get Pentests
|
||||||
|
* @param projectId the id of the project
|
||||||
|
* @param category the categories of which the pentests should be requested
|
||||||
|
*/
|
||||||
|
private getPentestByProjectIdAndCategory(projectId: string, category: Category): Observable<Pentest[]> {
|
||||||
|
return this.http.get<Pentest[]>(`${this.apiBaseURL}?projectId=${projectId}?category=${category}`);
|
||||||
|
}
|
||||||
|
}
|
|
@ -35,7 +35,6 @@ export class ProjectService {
|
||||||
* @param project the information of the project
|
* @param project the information of the project
|
||||||
*/
|
*/
|
||||||
public updateProject(projectId: string, project: ProjectDialogBody): Observable<Project> {
|
public updateProject(projectId: string, project: ProjectDialogBody): Observable<Project> {
|
||||||
console.log('update Project');
|
|
||||||
return this.http.patch<Project>(`${this.apiBaseURL}/${projectId}`, project);
|
return this.http.patch<Project>(`${this.apiBaseURL}/${projectId}`, project);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,45 @@
|
||||||
|
import {Injectable, Inject, NgModule, ModuleWithProviders, InjectionToken} from '@angular/core';
|
||||||
|
import {NgxsPlugin, NGXS_PLUGINS, getActionTypeFromInstance} from '@ngxs/store';
|
||||||
|
import {tap} from 'rxjs/operators';
|
||||||
|
|
||||||
|
export const NGXS_LOGGER_PLUGIN_OPTIONS = new InjectionToken('NGXS_LOGGER_PLUGIN_OPTIONS');
|
||||||
|
|
||||||
|
@Injectable()
|
||||||
|
export class LoggerPlugin implements NgxsPlugin {
|
||||||
|
constructor(@Inject(NGXS_LOGGER_PLUGIN_OPTIONS) private options: any) {
|
||||||
|
}
|
||||||
|
|
||||||
|
handle(state, action, next): any {
|
||||||
|
if (this.options?.developmentMode) {
|
||||||
|
const actionName = getActionTypeFromInstance(action);
|
||||||
|
// console.debug('@', actionName, 'started', state);
|
||||||
|
return next(state, action)
|
||||||
|
.pipe(tap(result => {
|
||||||
|
// tslint:disable-next-line:no-console
|
||||||
|
console.debug('@', actionName, ' - AFTER', result);
|
||||||
|
}));
|
||||||
|
} else {
|
||||||
|
return next(state, action);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@NgModule()
|
||||||
|
export class NgxsLoggerPluginModule {
|
||||||
|
static forRoot(config?: any): ModuleWithProviders<any> {
|
||||||
|
return {
|
||||||
|
ngModule: NgxsLoggerPluginModule,
|
||||||
|
providers: [
|
||||||
|
{
|
||||||
|
provide: NGXS_PLUGINS,
|
||||||
|
useClass: LoggerPlugin,
|
||||||
|
multi: true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
provide: NGXS_LOGGER_PLUGIN_OPTIONS,
|
||||||
|
useValue: config
|
||||||
|
}
|
||||||
|
]
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,34 @@
|
||||||
|
import {Project} from '@shared/models/project.model';
|
||||||
|
import {Category} from '@shared/models/category.model';
|
||||||
|
|
||||||
|
|
||||||
|
export class InitProjectState {
|
||||||
|
static readonly type = '[ProjectState] InitProjectState';
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
public project: Project,
|
||||||
|
public disabledCategories: Array<string>,
|
||||||
|
public disabledPentests: Array<string>) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export class ChangeProject {
|
||||||
|
static readonly type = '[ProjectState] ChangeProject';
|
||||||
|
|
||||||
|
constructor(public project: Project) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export class ChangeCategory {
|
||||||
|
static readonly type = '[ProjectState] ChangeCategory';
|
||||||
|
|
||||||
|
constructor(public category: Category) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export class ChangePentest {
|
||||||
|
static readonly type = '[ProjectState] ChangePentest';
|
||||||
|
|
||||||
|
constructor(public pentestId: string) {
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,56 @@
|
||||||
|
import {NgxsModule, Store} from '@ngxs/store';
|
||||||
|
import {TestBed} from '@angular/core/testing';
|
||||||
|
import {HttpClientTestingModule} from '@angular/common/http/testing';
|
||||||
|
import {TranslateLoader, TranslateModule} from '@ngx-translate/core';
|
||||||
|
import {HttpLoaderFactory} from '../../../app/common-app.module';
|
||||||
|
import {HttpClient} from '@angular/common/http';
|
||||||
|
import {PROJECT_STATE_NAME, ProjectState, ProjectStateModel} from '@shared/stores/project-state/project-state';
|
||||||
|
import {Category} from '@shared/models/category.model';
|
||||||
|
|
||||||
|
const INITIAL_PROJECT_STATE_SESSION: ProjectStateModel = {
|
||||||
|
selectedProject: null,
|
||||||
|
disabledCategories: [],
|
||||||
|
selectedCategory: Category.INFORMATION_GATHERING,
|
||||||
|
disabledPentests: [],
|
||||||
|
selectedPentestId: null
|
||||||
|
};
|
||||||
|
|
||||||
|
const DESIRED_PROJECT_STATE_SESSION: ProjectStateModel = {
|
||||||
|
selectedProject: null,
|
||||||
|
disabledCategories: [],
|
||||||
|
selectedCategory: Category.INFORMATION_GATHERING,
|
||||||
|
disabledPentests: [],
|
||||||
|
selectedPentestId: null
|
||||||
|
};
|
||||||
|
|
||||||
|
describe('SessionState', () => {
|
||||||
|
let store: Store;
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
TestBed.configureTestingModule({
|
||||||
|
imports: [
|
||||||
|
HttpClientTestingModule,
|
||||||
|
TranslateModule.forRoot({
|
||||||
|
loader: {
|
||||||
|
provide: TranslateLoader,
|
||||||
|
useFactory: HttpLoaderFactory,
|
||||||
|
deps: [HttpClient]
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
NgxsModule.forRoot([ProjectState]),
|
||||||
|
]
|
||||||
|
});
|
||||||
|
store = TestBed.inject(Store);
|
||||||
|
store.reset({
|
||||||
|
...store.snapshot(),
|
||||||
|
[PROJECT_STATE_NAME]: INITIAL_PROJECT_STATE_SESSION
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should contain store for PROJECT_STATE_NAME', (done) => {
|
||||||
|
store.selectSnapshot(state => {
|
||||||
|
expect(state[PROJECT_STATE_NAME]).toBeTruthy();
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
|
@ -0,0 +1,82 @@
|
||||||
|
import {Action, Selector, State, StateContext} from '@ngxs/store';
|
||||||
|
import {Injectable} from '@angular/core';
|
||||||
|
import {Project} from '@shared/models/project.model';
|
||||||
|
import {ChangeCategory, ChangePentest, ChangeProject, InitProjectState} from '@shared/stores/project-state/project-state.actions';
|
||||||
|
import {Category} from '@shared/models/category.model';
|
||||||
|
|
||||||
|
export const PROJECT_STATE_NAME = 'project';
|
||||||
|
|
||||||
|
export interface ProjectStateModel {
|
||||||
|
selectedProject: Project;
|
||||||
|
// Manages Categories
|
||||||
|
disabledCategories: Array<string>;
|
||||||
|
selectedCategory: Category;
|
||||||
|
// Manages Pentests of Category
|
||||||
|
disabledPentests: Array<string>;
|
||||||
|
selectedPentestId: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
@State<ProjectStateModel>({
|
||||||
|
name: PROJECT_STATE_NAME,
|
||||||
|
defaults: {
|
||||||
|
selectedProject: null,
|
||||||
|
disabledCategories: [],
|
||||||
|
selectedCategory: Category.INFORMATION_GATHERING,
|
||||||
|
disabledPentests: [],
|
||||||
|
selectedPentestId: null
|
||||||
|
}
|
||||||
|
})
|
||||||
|
@Injectable()
|
||||||
|
export class ProjectState {
|
||||||
|
@Selector()
|
||||||
|
static project(state: ProjectStateModel): Project {
|
||||||
|
return state.selectedProject;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Selector()
|
||||||
|
static selectedCategory(state: ProjectStateModel): Category {
|
||||||
|
return state.selectedCategory;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Selector()
|
||||||
|
static selectedPentestId(state: ProjectStateModel): string {
|
||||||
|
return state.selectedPentestId;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Action(InitProjectState)
|
||||||
|
initProjectState(ctx: StateContext<ProjectStateModel>, action: InitProjectState): void {
|
||||||
|
ctx.setState({
|
||||||
|
selectedProject: action.project,
|
||||||
|
disabledCategories: action.disabledCategories,
|
||||||
|
selectedCategory: Category.INFORMATION_GATHERING,
|
||||||
|
disabledPentests: action.disabledPentests,
|
||||||
|
selectedPentestId: null
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@Action(ChangeProject)
|
||||||
|
changeProject(ctx: StateContext<ProjectStateModel>, {project}: ChangeProject): void {
|
||||||
|
const state = ctx.getState();
|
||||||
|
// ToDo: Add logic to change selectedCategory if disabled
|
||||||
|
ctx.patchState({
|
||||||
|
selectedProject: project
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@Action(ChangeCategory)
|
||||||
|
changeCategory(ctx: StateContext<ProjectStateModel>, {category}: ChangeCategory): void {
|
||||||
|
const state = ctx.getState();
|
||||||
|
// ToDo: Add logic to change selectedCategory if disabled
|
||||||
|
ctx.patchState({
|
||||||
|
selectedCategory: category
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@Action(ChangePentest)
|
||||||
|
changePentest(ctx: StateContext<ProjectStateModel>, {pentestId}: ChangePentest): void {
|
||||||
|
const state = ctx.getState();
|
||||||
|
ctx.patchState({
|
||||||
|
selectedPentestId: pentestId
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,9 @@
|
||||||
|
<div class="finding-widget">
|
||||||
|
<ng-container *ngIf="numberOfFindigs > 0; else noFindings">
|
||||||
|
<fa-icon [icon]="fa.faExclamationCircle" size="lg" class="finding-icon"></fa-icon>
|
||||||
|
<span class="findings-count">{{numberOfFindigs}}</span>
|
||||||
|
</ng-container>
|
||||||
|
<ng-template #noFindings>
|
||||||
|
{{'-'}}
|
||||||
|
</ng-template>
|
||||||
|
</div>
|
|
@ -0,0 +1,14 @@
|
||||||
|
@import '../../../assets/@theme/styles/themes';
|
||||||
|
|
||||||
|
.finding-widget {
|
||||||
|
align-items: center;
|
||||||
|
|
||||||
|
.finding-icon {
|
||||||
|
color: nb-theme(color-danger-default);
|
||||||
|
}
|
||||||
|
|
||||||
|
.findings-count {
|
||||||
|
margin-left: 0.45rem;
|
||||||
|
color: nb-theme(color-danger-default);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,31 @@
|
||||||
|
import {ComponentFixture, TestBed} from '@angular/core/testing';
|
||||||
|
|
||||||
|
import {FindigWidgetComponent} from './findig-widget.component';
|
||||||
|
import {FontAwesomeTestingModule} from '@fortawesome/angular-fontawesome/testing';
|
||||||
|
|
||||||
|
describe('FindigWidgetComponent', () => {
|
||||||
|
let component: FindigWidgetComponent;
|
||||||
|
let fixture: ComponentFixture<FindigWidgetComponent>;
|
||||||
|
|
||||||
|
beforeEach(async () => {
|
||||||
|
await TestBed.configureTestingModule({
|
||||||
|
declarations: [
|
||||||
|
FindigWidgetComponent
|
||||||
|
],
|
||||||
|
imports: [
|
||||||
|
FontAwesomeTestingModule
|
||||||
|
]
|
||||||
|
})
|
||||||
|
.compileComponents();
|
||||||
|
});
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
fixture = TestBed.createComponent(FindigWidgetComponent);
|
||||||
|
component = fixture.componentInstance;
|
||||||
|
fixture.detectChanges();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should create', () => {
|
||||||
|
expect(component).toBeTruthy();
|
||||||
|
});
|
||||||
|
});
|
|
@ -0,0 +1,20 @@
|
||||||
|
import {Component, Input, OnInit} from '@angular/core';
|
||||||
|
import * as FA from '@fortawesome/free-solid-svg-icons';
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'app-findig-widget',
|
||||||
|
templateUrl: './findig-widget.component.html',
|
||||||
|
styleUrls: ['./findig-widget.component.scss']
|
||||||
|
})
|
||||||
|
export class FindigWidgetComponent implements OnInit {
|
||||||
|
@Input() numberOfFindigs: number;
|
||||||
|
|
||||||
|
// HTML only
|
||||||
|
readonly fa = FA;
|
||||||
|
|
||||||
|
constructor() { }
|
||||||
|
|
||||||
|
ngOnInit(): void {
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,19 @@
|
||||||
|
import {NgModule} from '@angular/core';
|
||||||
|
import {CommonModule} from '@angular/common';
|
||||||
|
import {FindigWidgetComponent} from '@shared/widgets/findig-widget/findig-widget.component';
|
||||||
|
import {FontAwesomeModule} from '@fortawesome/angular-fontawesome';
|
||||||
|
|
||||||
|
@NgModule({
|
||||||
|
declarations: [
|
||||||
|
FindigWidgetComponent
|
||||||
|
],
|
||||||
|
exports: [
|
||||||
|
FindigWidgetComponent
|
||||||
|
],
|
||||||
|
imports: [
|
||||||
|
CommonModule,
|
||||||
|
FontAwesomeModule
|
||||||
|
]
|
||||||
|
})
|
||||||
|
export class FindigWidgetModule {
|
||||||
|
}
|
|
@ -0,0 +1,12 @@
|
||||||
|
import { NgModule } from '@angular/core';
|
||||||
|
import { CommonModule } from '@angular/common';
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@NgModule({
|
||||||
|
declarations: [],
|
||||||
|
imports: [
|
||||||
|
CommonModule
|
||||||
|
]
|
||||||
|
})
|
||||||
|
export class FindigModule { }
|
|
@ -0,0 +1,16 @@
|
||||||
|
<ng-container [ngSwitch]="currentStatus">
|
||||||
|
<nb-tag-list>
|
||||||
|
<nb-tag *ngSwitchCase="status.OPEN" status="info" appearance="filled"
|
||||||
|
text="{{getTranslationKey() | translate}}"></nb-tag>
|
||||||
|
<nb-tag *ngSwitchCase="status.CHECKED" status="primary" 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>
|
||||||
|
<nb-tag *ngSwitchCase="status.TRIAGED" status="success" appearance="filled"
|
||||||
|
text="{{getTranslationKey() | translate}}"></nb-tag>
|
||||||
|
<nb-tag *ngSwitchDefault status="basic" appearance="filled"
|
||||||
|
text="{{getTranslationKey() | translate}}"></nb-tag>
|
||||||
|
</nb-tag-list>
|
||||||
|
</ng-container>
|
|
@ -0,0 +1,47 @@
|
||||||
|
import {ComponentFixture, TestBed} from '@angular/core/testing';
|
||||||
|
|
||||||
|
import {StatusTagComponent} from './status-tag.component';
|
||||||
|
import {TranslateLoader, TranslateModule} from '@ngx-translate/core';
|
||||||
|
import {HttpLoaderFactory} from '../../../app/common-app.module';
|
||||||
|
import {HttpClient} from '@angular/common/http';
|
||||||
|
import {NbCardModule, NbFocusMonitor, NbTagModule} from '@nebular/theme';
|
||||||
|
import {BrowserAnimationsModule} from '@angular/platform-browser/animations';
|
||||||
|
import {CommonModule} from '@angular/common';
|
||||||
|
import {MockModule} from 'ng-mocks';
|
||||||
|
import {HttpClientTestingModule} from '@angular/common/http/testing';
|
||||||
|
|
||||||
|
describe('StatusTagComponent', () => {
|
||||||
|
let component: StatusTagComponent;
|
||||||
|
let fixture: ComponentFixture<StatusTagComponent>;
|
||||||
|
|
||||||
|
beforeEach(async () => {
|
||||||
|
await TestBed.configureTestingModule({
|
||||||
|
declarations: [
|
||||||
|
StatusTagComponent
|
||||||
|
],
|
||||||
|
imports: [
|
||||||
|
HttpClientTestingModule,
|
||||||
|
NbCardModule,
|
||||||
|
MockModule(NbTagModule),
|
||||||
|
TranslateModule.forRoot({
|
||||||
|
loader: {
|
||||||
|
provide: TranslateLoader,
|
||||||
|
useFactory: HttpLoaderFactory,
|
||||||
|
deps: [HttpClient]
|
||||||
|
}
|
||||||
|
})
|
||||||
|
]
|
||||||
|
})
|
||||||
|
.compileComponents();
|
||||||
|
});
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
fixture = TestBed.createComponent(StatusTagComponent);
|
||||||
|
component = fixture.componentInstance;
|
||||||
|
fixture.detectChanges();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should create', () => {
|
||||||
|
expect(component).toBeTruthy();
|
||||||
|
});
|
||||||
|
});
|
|
@ -0,0 +1,40 @@
|
||||||
|
import {ChangeDetectionStrategy, Component, Input, OnInit} from '@angular/core';
|
||||||
|
import {Status} from '@shared/models/status.model';
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'app-status-tag',
|
||||||
|
templateUrl: './status-tag.component.html',
|
||||||
|
styleUrls: ['./status-tag.component.scss'],
|
||||||
|
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||||
|
})
|
||||||
|
export class StatusTagComponent implements OnInit {
|
||||||
|
@Input() currentStatus: Status = Status.NOT_STARTED;
|
||||||
|
|
||||||
|
// HTML only
|
||||||
|
status = Status;
|
||||||
|
readonly statusTexts: Array<StatusText> = [
|
||||||
|
{value: Status.NOT_STARTED, translationText: 'pentest.statusText.not_started'},
|
||||||
|
{value: Status.DISABLED, translationText: 'pentest.statusText.disabled'},
|
||||||
|
{value: Status.OPEN, translationText: 'pentest.statusText.open'},
|
||||||
|
{value: Status.CHECKED, translationText: 'pentest.statusText.checked'},
|
||||||
|
{value: Status.REPORTED, translationText: 'pentest.statusText.reported'},
|
||||||
|
{value: Status.UNDER_REVIEW, translationText: 'pentest.statusText.under_review'},
|
||||||
|
{value: Status.TRIAGED, translationText: 'pentest.statusText.triaged'}
|
||||||
|
];
|
||||||
|
|
||||||
|
constructor() { }
|
||||||
|
|
||||||
|
ngOnInit(): void {
|
||||||
|
}
|
||||||
|
|
||||||
|
getTranslationKey(): string {
|
||||||
|
const index = this.statusTexts.findIndex(statusText => statusText.value === this.currentStatus);
|
||||||
|
return this.statusTexts[index].translationText;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
interface StatusText {
|
||||||
|
value: string;
|
||||||
|
translationText: string;
|
||||||
|
}
|
|
@ -0,0 +1,22 @@
|
||||||
|
import {NgModule} from '@angular/core';
|
||||||
|
import {CommonModule} from '@angular/common';
|
||||||
|
import {StatusTagComponent} from '@shared/widgets/status-tag/status-tag.component';
|
||||||
|
import {NbCardModule, NbTagModule} from '@nebular/theme';
|
||||||
|
import {TranslateModule} from '@ngx-translate/core';
|
||||||
|
|
||||||
|
@NgModule({
|
||||||
|
declarations: [
|
||||||
|
StatusTagComponent
|
||||||
|
],
|
||||||
|
exports: [
|
||||||
|
StatusTagComponent
|
||||||
|
],
|
||||||
|
imports: [
|
||||||
|
CommonModule,
|
||||||
|
NbCardModule,
|
||||||
|
NbTagModule,
|
||||||
|
TranslateModule
|
||||||
|
]
|
||||||
|
})
|
||||||
|
export class StatusTagModule {
|
||||||
|
}
|
|
@ -6,7 +6,7 @@
|
||||||
"types": []
|
"types": []
|
||||||
},
|
},
|
||||||
"angularCompilerOptions": {
|
"angularCompilerOptions": {
|
||||||
"enableIvy": false
|
"enableIvy": true
|
||||||
},
|
},
|
||||||
"files": [
|
"files": [
|
||||||
"src/main.ts",
|
"src/main.ts",
|
||||||
|
|
Loading…
Reference in New Issue