feat: As a user I want a timer to track the time spent on each objective
This commit is contained in:
parent
4ca2828e0f
commit
3be43fa96e
|
@ -2305,27 +2305,48 @@
|
||||||
"integrity": "sha512-a/7BiSgobHAgBWeN7N0w+lAhInrGxksn13uK7231n2m8EDPE3BMCl9NZLTGrj9ZXfCmC6LM0QLqXidIizVQ6yg=="
|
"integrity": "sha512-a/7BiSgobHAgBWeN7N0w+lAhInrGxksn13uK7231n2m8EDPE3BMCl9NZLTGrj9ZXfCmC6LM0QLqXidIizVQ6yg=="
|
||||||
},
|
},
|
||||||
"@fortawesome/fontawesome-svg-core": {
|
"@fortawesome/fontawesome-svg-core": {
|
||||||
"version": "1.2.36",
|
"version": "6.3.0",
|
||||||
"resolved": "https://registry.npmjs.org/@fortawesome/fontawesome-svg-core/-/fontawesome-svg-core-1.2.36.tgz",
|
"resolved": "https://registry.npmjs.org/@fortawesome/fontawesome-svg-core/-/fontawesome-svg-core-6.3.0.tgz",
|
||||||
"integrity": "sha512-YUcsLQKYb6DmaJjIHdDWpBIGCcyE/W+p/LMGvjQem55Mm2XWVAP5kWTMKWLv9lwpCVjpLxPyOMOyUocP1GxrtA==",
|
"integrity": "sha512-uz9YifyKlixV6AcKlOX8WNdtF7l6nakGyLYxYaCa823bEBqyj/U2ssqtctO38itNEwXb8/lMzjdoJ+aaJuOdrw==",
|
||||||
"requires": {
|
"requires": {
|
||||||
"@fortawesome/fontawesome-common-types": "^0.2.36"
|
"@fortawesome/fontawesome-common-types": "6.3.0"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"@fortawesome/fontawesome-common-types": {
|
||||||
|
"version": "6.3.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@fortawesome/fontawesome-common-types/-/fontawesome-common-types-6.3.0.tgz",
|
||||||
|
"integrity": "sha512-4BC1NMoacEBzSXRwKjZ/X/gmnbp/HU5Qqat7E8xqorUtBFZS+bwfGH5/wqOC2K6GV0rgEobp3OjGRMa5fK9pFg=="
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"@fortawesome/free-regular-svg-icons": {
|
"@fortawesome/free-regular-svg-icons": {
|
||||||
"version": "5.15.4",
|
"version": "6.3.0",
|
||||||
"resolved": "https://registry.npmjs.org/@fortawesome/free-regular-svg-icons/-/free-regular-svg-icons-5.15.4.tgz",
|
"resolved": "https://registry.npmjs.org/@fortawesome/free-regular-svg-icons/-/free-regular-svg-icons-6.3.0.tgz",
|
||||||
"integrity": "sha512-9VNNnU3CXHy9XednJ3wzQp6SwNwT3XaM26oS4Rp391GsxVYA+0oDR2J194YCIWf7jNRCYKjUCOduxdceLrx+xw==",
|
"integrity": "sha512-cZnwiVHZ51SVzWHOaNCIA+u9wevZjCuAGSvSYpNlm6A4H4Vhwh8481Bf/5rwheIC3fFKlgXxLKaw8Xeroz8Ntg==",
|
||||||
"requires": {
|
"requires": {
|
||||||
"@fortawesome/fontawesome-common-types": "^0.2.36"
|
"@fortawesome/fontawesome-common-types": "6.3.0"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"@fortawesome/fontawesome-common-types": {
|
||||||
|
"version": "6.3.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@fortawesome/fontawesome-common-types/-/fontawesome-common-types-6.3.0.tgz",
|
||||||
|
"integrity": "sha512-4BC1NMoacEBzSXRwKjZ/X/gmnbp/HU5Qqat7E8xqorUtBFZS+bwfGH5/wqOC2K6GV0rgEobp3OjGRMa5fK9pFg=="
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"@fortawesome/free-solid-svg-icons": {
|
"@fortawesome/free-solid-svg-icons": {
|
||||||
"version": "5.15.4",
|
"version": "6.3.0",
|
||||||
"resolved": "https://registry.npmjs.org/@fortawesome/free-solid-svg-icons/-/free-solid-svg-icons-5.15.4.tgz",
|
"resolved": "https://registry.npmjs.org/@fortawesome/free-solid-svg-icons/-/free-solid-svg-icons-6.3.0.tgz",
|
||||||
"integrity": "sha512-JLmQfz6tdtwxoihXLg6lT78BorrFyCf59SAwBM6qV/0zXyVeDygJVb3fk+j5Qat+Yvcxp1buLTY5iDh1ZSAQ8w==",
|
"integrity": "sha512-x5tMwzF2lTH8pyv8yeZRodItP2IVlzzmBuD1M7BjawWgg9XAvktqJJ91Qjgoaf8qJpHQ8FEU9VxRfOkLhh86QA==",
|
||||||
"requires": {
|
"requires": {
|
||||||
"@fortawesome/fontawesome-common-types": "^0.2.36"
|
"@fortawesome/fontawesome-common-types": "6.3.0"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"@fortawesome/fontawesome-common-types": {
|
||||||
|
"version": "6.3.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@fortawesome/fontawesome-common-types/-/fontawesome-common-types-6.3.0.tgz",
|
||||||
|
"integrity": "sha512-4BC1NMoacEBzSXRwKjZ/X/gmnbp/HU5Qqat7E8xqorUtBFZS+bwfGH5/wqOC2K6GV0rgEobp3OjGRMa5fK9pFg=="
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"@istanbuljs/load-nyc-config": {
|
"@istanbuljs/load-nyc-config": {
|
||||||
|
|
|
@ -24,9 +24,9 @@
|
||||||
"@angular/router": "~12.2.16",
|
"@angular/router": "~12.2.16",
|
||||||
"@fortawesome/angular-fontawesome": "^0.8.2",
|
"@fortawesome/angular-fontawesome": "^0.8.2",
|
||||||
"@fortawesome/fontawesome-common-types": "^0.2.36",
|
"@fortawesome/fontawesome-common-types": "^0.2.36",
|
||||||
"@fortawesome/fontawesome-svg-core": "^1.2.36",
|
"@fortawesome/fontawesome-svg-core": "^6.3.0",
|
||||||
"@fortawesome/free-regular-svg-icons": "^5.15.4",
|
"@fortawesome/free-regular-svg-icons": "^6.3.0",
|
||||||
"@fortawesome/free-solid-svg-icons": "^5.15.4",
|
"@fortawesome/free-solid-svg-icons": "^6.3.0",
|
||||||
"@nebular/eva-icons": "^8.0.0",
|
"@nebular/eva-icons": "^8.0.0",
|
||||||
"@nebular/theme": "^8.0.0",
|
"@nebular/theme": "^8.0.0",
|
||||||
"@ngneat/until-destroy": "~8.0.4",
|
"@ngneat/until-destroy": "~8.0.4",
|
||||||
|
|
|
@ -1,11 +1,14 @@
|
||||||
import {Component, OnDestroy, OnInit} from '@angular/core';
|
import {Component, OnDestroy, OnInit} from '@angular/core';
|
||||||
import {NbMenuItem, NbMenuService} from '@nebular/theme';
|
import {NbMenuItem, NbMenuService} from '@nebular/theme';
|
||||||
import {Subject} from 'rxjs';
|
import {of, Subject} from 'rxjs';
|
||||||
import {Store} from '@ngxs/store';
|
import {Store} from '@ngxs/store';
|
||||||
import {ChangeCategory} from '@shared/stores/project-state/project-state.actions';
|
import {ChangeCategory} from '@shared/stores/project-state/project-state.actions';
|
||||||
import {Category} from '@shared/models/category.model';
|
import {Category} from '@shared/models/category.model';
|
||||||
import {untilDestroyed} from 'ngx-take-until-destroy';
|
import {untilDestroyed} from 'ngx-take-until-destroy';
|
||||||
import {TranslateService} from '@ngx-translate/core';
|
import {TranslateService} from '@ngx-translate/core';
|
||||||
|
import {ProjectState} from '@shared/stores/project-state/project-state';
|
||||||
|
import {catchError, switchMap, tap} from 'rxjs/operators';
|
||||||
|
import {Pentest, transformPentestsToObjectiveEntries} from '@shared/models/pentest.model';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-objective-categories',
|
selector: 'app-objective-categories',
|
||||||
|
@ -25,8 +28,22 @@ export class ObjectiveCategoriesComponent implements OnInit, OnDestroy {
|
||||||
|
|
||||||
ngOnInit(): void {
|
ngOnInit(): void {
|
||||||
this.initTranslation();
|
this.initTranslation();
|
||||||
// Set first item in list as selected
|
this.store.select(ProjectState.selectedCategory).pipe(
|
||||||
this.categories[0].selected = true;
|
untilDestroyed(this)
|
||||||
|
).subscribe({
|
||||||
|
next: (categoryIndex) => {
|
||||||
|
if (categoryIndex) {
|
||||||
|
this.selectedCategory = categoryIndex;
|
||||||
|
this.categories[categoryIndex].selected = true;
|
||||||
|
} else {
|
||||||
|
// Set first item in list as selected
|
||||||
|
this.categories[0].selected = true;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
error: error => {
|
||||||
|
console.error(error);
|
||||||
|
}
|
||||||
|
});
|
||||||
this.menuService.onItemClick()
|
this.menuService.onItemClick()
|
||||||
.pipe(
|
.pipe(
|
||||||
untilDestroyed(this)
|
untilDestroyed(this)
|
||||||
|
|
|
@ -5,17 +5,8 @@
|
||||||
class="comment-cell"
|
class="comment-cell"
|
||||||
fragment="{{comment.data['commentId']}}">
|
fragment="{{comment.data['commentId']}}">
|
||||||
</tr>
|
</tr>
|
||||||
<!-- Comment ID -->
|
|
||||||
<ng-container [nbTreeGridColumnDef]="columns[0]">
|
|
||||||
<th nbTreeGridHeaderCell *nbTreeGridHeaderCellDef>
|
|
||||||
{{ 'comment.commentId' | translate }}
|
|
||||||
</th>
|
|
||||||
<td nbTreeGridCell *nbTreeGridCellDef="let comment">
|
|
||||||
{{ comment.data['commentId'] || '-' }}
|
|
||||||
</td>
|
|
||||||
</ng-container>
|
|
||||||
<!-- Title -->
|
<!-- Title -->
|
||||||
<ng-container [nbTreeGridColumnDef]="columns[1]">
|
<ng-container [nbTreeGridColumnDef]="columns[0]">
|
||||||
<th nbTreeGridHeaderCell *nbTreeGridHeaderCellDef>
|
<th nbTreeGridHeaderCell *nbTreeGridHeaderCellDef>
|
||||||
{{ 'comment.title' | translate }}
|
{{ 'comment.title' | translate }}
|
||||||
</th>
|
</th>
|
||||||
|
@ -24,7 +15,7 @@
|
||||||
</td>
|
</td>
|
||||||
</ng-container>
|
</ng-container>
|
||||||
<!-- Description -->
|
<!-- Description -->
|
||||||
<ng-container [nbTreeGridColumnDef]="columns[2]">
|
<ng-container [nbTreeGridColumnDef]="columns[1]">
|
||||||
<th nbTreeGridHeaderCell *nbTreeGridHeaderCellDef>
|
<th nbTreeGridHeaderCell *nbTreeGridHeaderCellDef>
|
||||||
{{ 'comment.description' | translate }}
|
{{ 'comment.description' | translate }}
|
||||||
</th>
|
</th>
|
||||||
|
@ -32,29 +23,15 @@
|
||||||
{{ comment.data['description'] }}
|
{{ comment.data['description'] }}
|
||||||
</td>
|
</td>
|
||||||
</ng-container>
|
</ng-container>
|
||||||
<!-- Related Findings -->
|
|
||||||
<ng-container [nbTreeGridColumnDef]="columns[3]">
|
|
||||||
<th nbTreeGridHeaderCell *nbTreeGridHeaderCellDef>
|
|
||||||
{{ 'comment.relatedFindings' | translate }}
|
|
||||||
</th>
|
|
||||||
<td nbTreeGridCell *nbTreeGridCellDef="let comment" class="related-finding-cell">
|
|
||||||
<ng-container *ngIf="comment.data['relatedFindings'].length > 0; else NoRelatedFindings">
|
|
||||||
<app-findig-widget [numberOfFindings]="comment.data['relatedFindings'].length"></app-findig-widget>
|
|
||||||
</ng-container>
|
|
||||||
<ng-template #NoRelatedFindings>
|
|
||||||
{{ 'comment.no.relatedFindings' | translate }}
|
|
||||||
</ng-template>
|
|
||||||
</td>
|
|
||||||
</ng-container>
|
|
||||||
<!-- Actions -->
|
<!-- Actions -->
|
||||||
<ng-container [nbTreeGridColumnDef]="columns[4]">
|
<ng-container [nbTreeGridColumnDef]="columns[2]">
|
||||||
<th nbTreeGridHeaderCell *nbTreeGridHeaderCellDef class="cell-actions">
|
<th nbTreeGridHeaderCell *nbTreeGridHeaderCellDef class="cell-actions">
|
||||||
<button nbButton hero
|
<button nbButton hero
|
||||||
status="info"
|
status="info"
|
||||||
size="small"
|
size="small"
|
||||||
shape="round"
|
shape="round"
|
||||||
class="add-comment-button"
|
class="add-comment-button"
|
||||||
[disabled]="pentestInfo$.getValue().status === notStartedStatus"
|
[disabled]="pentestInfo$.getValue().status !== inProgressStatus"
|
||||||
(click)="onClickAddComment()">
|
(click)="onClickAddComment()">
|
||||||
<fa-icon [icon]="fa.faPlus" class="new-comment-icon"></fa-icon>
|
<fa-icon [icon]="fa.faPlus" class="new-comment-icon"></fa-icon>
|
||||||
{{'comment.add' | translate}}
|
{{'comment.add' | translate}}
|
||||||
|
|
|
@ -9,7 +9,7 @@ import {catchError, filter, mergeMap, switchMap, tap} from 'rxjs/operators';
|
||||||
import {
|
import {
|
||||||
Comment,
|
Comment,
|
||||||
CommentDialogBody,
|
CommentDialogBody,
|
||||||
CommentEntry, RelatedFindingOption,
|
CommentEntry,
|
||||||
transformCommentsToObjectiveEntries,
|
transformCommentsToObjectiveEntries,
|
||||||
transformCommentToRequestBody
|
transformCommentToRequestBody
|
||||||
} from '@shared/models/comment.model';
|
} from '@shared/models/comment.model';
|
||||||
|
@ -35,15 +35,15 @@ export class PentestCommentsComponent implements OnInit {
|
||||||
|
|
||||||
// HTML only
|
// HTML only
|
||||||
readonly fa = FA;
|
readonly fa = FA;
|
||||||
notStartedStatus: PentestStatus = PentestStatus.NOT_STARTED;
|
// HTML only for button enabling
|
||||||
|
inProgressStatus: PentestStatus = PentestStatus.IN_PROGRESS;
|
||||||
|
|
||||||
pentestInfo$: BehaviorSubject<Pentest> = new BehaviorSubject<Pentest>(null);
|
pentestInfo$: BehaviorSubject<Pentest> = new BehaviorSubject<Pentest>(null);
|
||||||
objectiveFindings: RelatedFindingOption[] = [];
|
|
||||||
// comments$: BehaviorSubject<Comment[]> = new BehaviorSubject<Comment[]>(null);
|
// comments$: BehaviorSubject<Comment[]> = new BehaviorSubject<Comment[]>(null);
|
||||||
loading$: BehaviorSubject<boolean> = new BehaviorSubject<boolean>(true);
|
loading$: BehaviorSubject<boolean> = new BehaviorSubject<boolean>(true);
|
||||||
|
|
||||||
columns: Array<CommentColumns> = [
|
columns: Array<CommentColumns> = [
|
||||||
CommentColumns.COMMENT_ID, CommentColumns.TITLE, CommentColumns.DESCRIPTION, CommentColumns.RELATED_FINDINGS, CommentColumns.ACTIONS
|
CommentColumns.TITLE, CommentColumns.DESCRIPTION, CommentColumns.ACTIONS
|
||||||
];
|
];
|
||||||
dataSource: NbTreeGridDataSource<CommentEntry>;
|
dataSource: NbTreeGridDataSource<CommentEntry>;
|
||||||
data: CommentEntry[] = [];
|
data: CommentEntry[] = [];
|
||||||
|
@ -109,7 +109,6 @@ export class PentestCommentsComponent implements OnInit {
|
||||||
this.commentDialogService.openCommentDialog(
|
this.commentDialogService.openCommentDialog(
|
||||||
CommentDialogComponent,
|
CommentDialogComponent,
|
||||||
this.pentestInfo$.getValue().findingIds,
|
this.pentestInfo$.getValue().findingIds,
|
||||||
this.objectiveFindings,
|
|
||||||
null,
|
null,
|
||||||
{
|
{
|
||||||
closeOnEsc: false,
|
closeOnEsc: false,
|
||||||
|
@ -149,7 +148,6 @@ export class PentestCommentsComponent implements OnInit {
|
||||||
this.commentDialogService.openCommentDialog(
|
this.commentDialogService.openCommentDialog(
|
||||||
CommentDialogComponent,
|
CommentDialogComponent,
|
||||||
this.pentestInfo$.getValue().findingIds,
|
this.pentestInfo$.getValue().findingIds,
|
||||||
this.objectiveFindings,
|
|
||||||
existingComment,
|
existingComment,
|
||||||
{
|
{
|
||||||
closeOnEsc: false,
|
closeOnEsc: false,
|
||||||
|
@ -187,12 +185,11 @@ export class PentestCommentsComponent implements OnInit {
|
||||||
}
|
}
|
||||||
|
|
||||||
requestFindingsData(pentestId: string): void {
|
requestFindingsData(pentestId: string): void {
|
||||||
this.objectiveFindings = [];
|
|
||||||
this.findingService.getFindingsByPentestId(pentestId).pipe(
|
this.findingService.getFindingsByPentestId(pentestId).pipe(
|
||||||
untilDestroyed(this)
|
untilDestroyed(this)
|
||||||
).subscribe({
|
).subscribe({
|
||||||
next: (findings: Finding[]) => {
|
next: (findings: Finding[]) => {
|
||||||
findings.forEach(finding => this.objectiveFindings.push({id: finding.id, title: finding.title} as RelatedFindingOption));
|
// findings.forEach(finding => this.objectiveFindings.push({id: finding.id, title: finding.title} as RelatedFindingOption));
|
||||||
},
|
},
|
||||||
error: err => {
|
error: err => {
|
||||||
console.error(err);
|
console.error(err);
|
||||||
|
|
|
@ -5,13 +5,13 @@
|
||||||
class="finding-cell"
|
class="finding-cell"
|
||||||
fragment="{{finding.data['findingId']}}">
|
fragment="{{finding.data['findingId']}}">
|
||||||
</tr>
|
</tr>
|
||||||
<!-- Finding ID -->
|
<!-- Title -->
|
||||||
<ng-container [nbTreeGridColumnDef]="columns[0]">
|
<ng-container [nbTreeGridColumnDef]="columns[0]">
|
||||||
<th nbTreeGridHeaderCell *nbTreeGridHeaderCellDef>
|
<th nbTreeGridHeaderCell *nbTreeGridHeaderCellDef>
|
||||||
{{ 'finding.findingId' | translate }}
|
{{ 'finding.title' | translate }}
|
||||||
</th>
|
</th>
|
||||||
<td nbTreeGridCell *nbTreeGridCellDef="let finding">
|
<td nbTreeGridCell *nbTreeGridCellDef="let finding">
|
||||||
{{ finding.data['findingId'] || '-' }}
|
{{ finding.data['title'] }}
|
||||||
</td>
|
</td>
|
||||||
</ng-container>
|
</ng-container>
|
||||||
<!-- Severity -->
|
<!-- Severity -->
|
||||||
|
@ -25,13 +25,13 @@
|
||||||
</ng-container>
|
</ng-container>
|
||||||
</td>
|
</td>
|
||||||
</ng-container>
|
</ng-container>
|
||||||
<!-- Title -->
|
<!-- Description -->
|
||||||
<ng-container [nbTreeGridColumnDef]="columns[2]">
|
<ng-container [nbTreeGridColumnDef]="columns[2]">
|
||||||
<th nbTreeGridHeaderCell *nbTreeGridHeaderCellDef>
|
<th nbTreeGridHeaderCell *nbTreeGridHeaderCellDef>
|
||||||
{{ 'finding.title' | translate }}
|
{{ 'finding.description' | translate }}
|
||||||
</th>
|
</th>
|
||||||
<td nbTreeGridCell *nbTreeGridCellDef="let finding">
|
<td nbTreeGridCell *nbTreeGridCellDef="let finding">
|
||||||
{{ finding.data['title'] }}
|
{{ finding.data['description'] }}
|
||||||
</td>
|
</td>
|
||||||
</ng-container>
|
</ng-container>
|
||||||
<!-- Impact -->
|
<!-- Impact -->
|
||||||
|
@ -51,7 +51,7 @@
|
||||||
size="small"
|
size="small"
|
||||||
shape="round"
|
shape="round"
|
||||||
class="add-finding-button"
|
class="add-finding-button"
|
||||||
[disabled]="pentestInfo$.getValue().status === notStartedStatus"
|
[disabled]="pentestInfo$.getValue().status !== inProgressStatus"
|
||||||
(click)="onClickAddFinding()">
|
(click)="onClickAddFinding()">
|
||||||
<fa-icon [icon]="fa.faPlus" class="new-finding-icon"></fa-icon>
|
<fa-icon [icon]="fa.faPlus" class="new-finding-icon"></fa-icon>
|
||||||
{{'finding.add' | translate}}
|
{{'finding.add' | translate}}
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
import {Component, OnInit} from '@angular/core';
|
import {Component, OnInit} from '@angular/core';
|
||||||
import {PentestService} from '@shared/services/api/pentest.service';
|
|
||||||
import {BehaviorSubject, Observable} from 'rxjs';
|
import {BehaviorSubject, Observable} from 'rxjs';
|
||||||
import {Pentest} from '@shared/models/pentest.model';
|
import {Pentest} from '@shared/models/pentest.model';
|
||||||
import {UntilDestroy, untilDestroyed} from '@ngneat/until-destroy';
|
import {UntilDestroy, untilDestroyed} from '@ngneat/until-destroy';
|
||||||
|
@ -46,10 +45,11 @@ export class PentestFindingsComponent implements OnInit {
|
||||||
|
|
||||||
// HTML only
|
// HTML only
|
||||||
readonly fa = FA;
|
readonly fa = FA;
|
||||||
notStartedStatus: PentestStatus = PentestStatus.NOT_STARTED;
|
// HTML only for button enabling
|
||||||
|
inProgressStatus: PentestStatus = PentestStatus.IN_PROGRESS;
|
||||||
|
|
||||||
columns: Array<FindingColumns> = [
|
columns: Array<FindingColumns> = [
|
||||||
FindingColumns.FINDING_ID, FindingColumns.SEVERITY, FindingColumns.TITLE, FindingColumns.IMPACT, FindingColumns.ACTIONS
|
FindingColumns.TITLE, FindingColumns.SEVERITY, FindingColumns.DESCRIPTION, FindingColumns.IMPACT, FindingColumns.ACTIONS
|
||||||
];
|
];
|
||||||
dataSource: NbTreeGridDataSource<FindingEntry>;
|
dataSource: NbTreeGridDataSource<FindingEntry>;
|
||||||
|
|
||||||
|
@ -218,8 +218,9 @@ export class PentestFindingsComponent implements OnInit {
|
||||||
|
|
||||||
enum FindingColumns {
|
enum FindingColumns {
|
||||||
FINDING_ID = 'findingId',
|
FINDING_ID = 'findingId',
|
||||||
SEVERITY = 'severity',
|
|
||||||
TITLE = 'title',
|
TITLE = 'title',
|
||||||
|
SEVERITY = 'severity',
|
||||||
|
DESCRIPTION = 'description',
|
||||||
IMPACT = 'impact',
|
IMPACT = 'impact',
|
||||||
ACTIONS = 'actions'
|
ACTIONS = 'actions'
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,42 +13,23 @@
|
||||||
|
|
||||||
<h4>{{selectedProjectTitle$.getValue()}} / {{pentest$.getValue().refNumber}}</h4>
|
<h4>{{selectedProjectTitle$.getValue()}} / {{pentest$.getValue().refNumber}}</h4>
|
||||||
|
|
||||||
<div class="pentest-status-container">
|
<div class="pentest-status-container" fxLayout="row" fxLayoutGap="2.5rem" fxLayoutAlign="end center">
|
||||||
<!--ToDo: Add changing dialog here-->
|
<!-- Pentest Timer-->
|
||||||
<!--<app-status-tag [currentStatus]="pentest$.getValue().status"></app-status-tag>-->
|
<div class="timer-component">
|
||||||
|
<app-timer></app-timer>
|
||||||
<!-- Pentest Status Selection -->
|
|
||||||
<div class="pentest-status-dialog">
|
|
||||||
<nb-select class="status"
|
|
||||||
[(selected)]="currentStatus"
|
|
||||||
shape="round" filled
|
|
||||||
status="{{getPentestFillStatus(currentStatus)}}">
|
|
||||||
<nb-option *ngFor="let status of statusTexts" [value]="status.value">
|
|
||||||
{{ status.translationText | translate }}
|
|
||||||
</nb-option>
|
|
||||||
</nb-select>
|
|
||||||
</div>
|
</div>
|
||||||
<div *ngIf="!pentest$.getValue().id; else updatePentest">
|
<!-- Complete Pentest -->
|
||||||
|
<div>
|
||||||
<button nbButton
|
<button nbButton
|
||||||
class="save-pentest-button"
|
class="save-pentest-button"
|
||||||
status="primary"
|
status="success"
|
||||||
[disabled]="!pentestStatusChanged()"
|
[disabled]="!pentestStatusChanged() || !pentestHasFindingsOrComments()"
|
||||||
title="{{ 'global.action.save' | translate }}"
|
title="{{ 'global.action.save' | translate }}"
|
||||||
(click)="onClickSavePentest()">
|
(click)="onClickCompletePentestAndRouteBack()">
|
||||||
<span class="exit-element-text"> {{ 'global.action.save' | translate }} </span>
|
<fa-icon [icon]="fa.faSquare"></fa-icon>
|
||||||
|
<span class="action-element-text"> {{ 'global.action.complete' | translate }} </span>
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
<ng-template #updatePentest>
|
|
||||||
<button nbButton
|
|
||||||
class="save-pentest-button"
|
|
||||||
status="primary"
|
|
||||||
[disabled]="!pentestStatusChanged()"
|
|
||||||
title="{{ 'global.action.update' | translate }}"
|
|
||||||
(click)="onClickUpdatePentest()">
|
|
||||||
<span class="exit-element-text"> {{ 'global.action.update' | translate }} </span>
|
|
||||||
</button>
|
|
||||||
</ng-template>
|
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
|
@ -11,10 +11,18 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
.pentest-status-container {
|
.pentest-status-container {
|
||||||
display: flex;
|
// display: flex;
|
||||||
align-content: flex-end;
|
// align-content: flex-end;
|
||||||
// margin-right: 0.5rem;
|
|
||||||
// height: 5%;
|
.timer-component {
|
||||||
|
height: 2rem !important;
|
||||||
|
max-height: 2rem !important;
|
||||||
|
margin: 0.5rem 2.25rem 1rem 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.action-element-text {
|
||||||
|
padding-left: 0.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
.pentest-status-dialog {
|
.pentest-status-dialog {
|
||||||
margin: 1rem 2.25rem 1rem 0;
|
margin: 1rem 2.25rem 1rem 0;
|
||||||
|
@ -41,6 +49,7 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
.save-pentest-button {
|
.save-pentest-button {
|
||||||
|
// height: 1rem !important;
|
||||||
margin: 1rem 0 1rem 0;
|
margin: 1rem 0 1rem 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import {Component, OnInit} from '@angular/core';
|
import {Component, OnDestroy, OnInit} from '@angular/core';
|
||||||
import * as FA from '@fortawesome/free-solid-svg-icons';
|
import * as FA from '@fortawesome/free-solid-svg-icons';
|
||||||
import {UntilDestroy, untilDestroyed} from '@ngneat/until-destroy';
|
import {UntilDestroy, untilDestroyed} from '@ngneat/until-destroy';
|
||||||
import {Route} from '@shared/models/route.enum';
|
import {Route} from '@shared/models/route.enum';
|
||||||
|
@ -20,7 +20,7 @@ import {StatusText} from '@shared/widgets/status-tag/status-tag.component';
|
||||||
templateUrl: './pentest-header.component.html',
|
templateUrl: './pentest-header.component.html',
|
||||||
styleUrls: ['./pentest-header.component.scss']
|
styleUrls: ['./pentest-header.component.scss']
|
||||||
})
|
})
|
||||||
export class PentestHeaderComponent implements OnInit {
|
export class PentestHeaderComponent implements OnInit, OnDestroy {
|
||||||
// HTML only
|
// HTML only
|
||||||
readonly fa = FA;
|
readonly fa = FA;
|
||||||
|
|
||||||
|
@ -28,16 +28,21 @@ export class PentestHeaderComponent implements OnInit {
|
||||||
selectedProjectTitle$: BehaviorSubject<string> = new BehaviorSubject<string>('');
|
selectedProjectTitle$: BehaviorSubject<string> = new BehaviorSubject<string>('');
|
||||||
pentestChanged$: BehaviorSubject<boolean> = new BehaviorSubject<boolean>(false);
|
pentestChanged$: BehaviorSubject<boolean> = new BehaviorSubject<boolean>(false);
|
||||||
|
|
||||||
|
// Pentest Timer Handler
|
||||||
|
currentTimeSpent = 0;
|
||||||
|
private initialTimeSpent: number;
|
||||||
|
|
||||||
// Pentest Status Handler
|
// Pentest Status Handler
|
||||||
status = PentestStatus;
|
status = PentestStatus;
|
||||||
currentStatus: PentestStatus = PentestStatus.NOT_STARTED;
|
currentStatus: PentestStatus = PentestStatus.NOT_STARTED;
|
||||||
private initialPentestStatus: PentestStatus;
|
private initialPentestStatus: PentestStatus;
|
||||||
|
|
||||||
// Status Text Translation Texts
|
// Status Text Translation Texts
|
||||||
readonly statusTexts: Array<StatusText> = [
|
readonly statusTexts: Array<StatusText> = [
|
||||||
{value: PentestStatus.NOT_STARTED, translationText: 'pentest.statusText.not_started'},
|
{value: PentestStatus.NOT_STARTED, translationText: 'pentest.statusText.not_started'},
|
||||||
/* ToDo: Disabled not needed inside pentest */
|
/* ToDo: Disabled not needed inside pentest */
|
||||||
/*{value: PentestStatus.DISABLED, translationText: 'pentest.statusText.disabled'},*/
|
/*{value: PentestStatus.DISABLED, translationText: 'pentest.statusText.disabled'},*/
|
||||||
{value: PentestStatus.OPEN, translationText: 'pentest.statusText.open'},
|
{value: PentestStatus.PAUSED, translationText: 'pentest.statusText.paused'},
|
||||||
{value: PentestStatus.IN_PROGRESS, translationText: 'pentest.statusText.in_progress'},
|
{value: PentestStatus.IN_PROGRESS, translationText: 'pentest.statusText.in_progress'},
|
||||||
{value: PentestStatus.COMPLETED, translationText: 'pentest.statusText.completed'}
|
{value: PentestStatus.COMPLETED, translationText: 'pentest.statusText.completed'}
|
||||||
];
|
];
|
||||||
|
@ -51,7 +56,7 @@ export class PentestHeaderComponent implements OnInit {
|
||||||
}
|
}
|
||||||
|
|
||||||
ngOnInit(): void {
|
ngOnInit(): void {
|
||||||
this.store.select(ProjectState.project).pipe(
|
this.store.selectOnce(ProjectState.project).pipe(
|
||||||
untilDestroyed(this)
|
untilDestroyed(this)
|
||||||
).subscribe({
|
).subscribe({
|
||||||
next: (selectedProject: Project) => {
|
next: (selectedProject: Project) => {
|
||||||
|
@ -68,17 +73,20 @@ export class PentestHeaderComponent implements OnInit {
|
||||||
).subscribe({
|
).subscribe({
|
||||||
next: (selectedPentest: Pentest) => {
|
next: (selectedPentest: Pentest) => {
|
||||||
this.currentStatus = selectedPentest.status;
|
this.currentStatus = selectedPentest.status;
|
||||||
this.initialPentestStatus = selectedPentest.status;
|
this.currentTimeSpent = selectedPentest.timeSpent ? selectedPentest.timeSpent : 0;
|
||||||
this.pentest$.next(selectedPentest);
|
this.pentest$.next(selectedPentest);
|
||||||
},
|
},
|
||||||
error: err => {
|
error: err => {
|
||||||
console.error(err);
|
console.error(err);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
// Setup initial values for status and time outside of store subscription
|
||||||
|
this.initialPentestStatus = this.currentStatus;
|
||||||
|
this.initialTimeSpent = this.currentTimeSpent;
|
||||||
}
|
}
|
||||||
|
|
||||||
onClickRouteBack(): void {
|
onClickRouteBack(): void {
|
||||||
// ToDo: Change to Objective Overview after routing is fixed
|
// Route back to overview
|
||||||
this.router.navigate([Route.OBJECTIVE_OVERVIEW])
|
this.router.navigate([Route.OBJECTIVE_OVERVIEW])
|
||||||
.then(
|
.then(
|
||||||
() => {
|
() => {
|
||||||
|
@ -87,27 +95,18 @@ export class PentestHeaderComponent implements OnInit {
|
||||||
).finally();
|
).finally();
|
||||||
}
|
}
|
||||||
|
|
||||||
onClickSavePentest(): void {
|
onClickCompletePentestAndRouteBack(): void {
|
||||||
this.pentest$.next({...this.pentest$.getValue(), status: this.currentStatus});
|
// Update existing Pentest
|
||||||
this.pentestService.savePentest(this.selectedProjectId$.getValue(), transformPentestToRequestBody(this.pentest$.getValue()))
|
this.pentest$.next({...this.pentest$.getValue(), status: PentestStatus.COMPLETED, timeSpent: this.currentTimeSpent});
|
||||||
.subscribe({
|
this.updatePentest();
|
||||||
next: (pentest: Pentest) => {
|
|
||||||
this.store.dispatch(new ChangePentest(pentest));
|
|
||||||
this.notificationService.showPopup('pentest.popup.save.success', PopupType.SUCCESS);
|
|
||||||
},
|
|
||||||
error: err => {
|
|
||||||
console.log(err);
|
|
||||||
this.notificationService.showPopup('pentest.popup.save.failed', PopupType.FAILURE);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
onClickUpdatePentest(): void {
|
private updatePentest(): void {
|
||||||
this.pentest$.next({...this.pentest$.getValue(), status: this.currentStatus});
|
|
||||||
this.pentestService.updatePentest(transformPentestToRequestBody(this.pentest$.getValue()))
|
this.pentestService.updatePentest(transformPentestToRequestBody(this.pentest$.getValue()))
|
||||||
.subscribe({
|
.subscribe({
|
||||||
next: (pentest: Pentest) => {
|
next: (pentest: Pentest) => {
|
||||||
this.store.dispatch(new ChangePentest(pentest));
|
this.store.dispatch(new ChangePentest(pentest));
|
||||||
|
this.initialTimeSpent = pentest.timeSpent;
|
||||||
this.notificationService.showPopup('pentest.popup.update.success', PopupType.SUCCESS);
|
this.notificationService.showPopup('pentest.popup.update.success', PopupType.SUCCESS);
|
||||||
},
|
},
|
||||||
error: err => {
|
error: err => {
|
||||||
|
@ -121,7 +120,7 @@ export class PentestHeaderComponent implements OnInit {
|
||||||
* @return true if initial pentest Status is different from current pentest status
|
* @return true if initial pentest Status is different from current pentest status
|
||||||
*/
|
*/
|
||||||
pentestStatusChanged(): boolean {
|
pentestStatusChanged(): boolean {
|
||||||
if (this.initialPentestStatus !== this.currentStatus) {
|
if (this.initialTimeSpent !== this.currentTimeSpent && this.currentTimeSpent !== 0) {
|
||||||
this.pentestChanged$.next(true);
|
this.pentestChanged$.next(true);
|
||||||
} else {
|
} else {
|
||||||
this.pentestChanged$.next(false);
|
this.pentestChanged$.next(false);
|
||||||
|
@ -129,6 +128,15 @@ export class PentestHeaderComponent implements OnInit {
|
||||||
return this.pentestChanged$.getValue();
|
return this.pentestChanged$.getValue();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return true if pentest includes at least one finding or comment
|
||||||
|
*/
|
||||||
|
pentestHasFindingsOrComments(): boolean {
|
||||||
|
const pentest: Pentest = this.pentest$.getValue();
|
||||||
|
// Check if pentest includes any findings or comments
|
||||||
|
return pentest?.findingIds?.length > 0 || pentest?.commentIds?.length > 0;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return the correct nb-status for current pentest-status
|
* @return the correct nb-status for current pentest-status
|
||||||
*/
|
*/
|
||||||
|
@ -139,7 +147,7 @@ export class PentestHeaderComponent implements OnInit {
|
||||||
pentestFillStatus = 'basic';
|
pentestFillStatus = 'basic';
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case PentestStatus.OPEN: {
|
case PentestStatus.PAUSED: {
|
||||||
pentestFillStatus = 'info';
|
pentestFillStatus = 'info';
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -158,4 +166,12 @@ export class PentestHeaderComponent implements OnInit {
|
||||||
}
|
}
|
||||||
return pentestFillStatus;
|
return pentestFillStatus;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ngOnDestroy(): void {
|
||||||
|
if (this.pentestStatusChanged()) {
|
||||||
|
// Save current Pentest before exiting
|
||||||
|
this.pentest$.next({...this.pentest$.getValue(), status: PentestStatus.PAUSED, timeSpent: this.currentTimeSpent});
|
||||||
|
this.updatePentest();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,6 +17,7 @@ import {SeverityTagModule} from '@shared/widgets/severity-tag/severity-tag.modul
|
||||||
import {FindingDialogModule} from '@shared/modules/finding-dialog/finding-dialog.module';
|
import {FindingDialogModule} from '@shared/modules/finding-dialog/finding-dialog.module';
|
||||||
import {CommentDialogModule} from '@shared/modules/comment-dialog/comment-dialog.module';
|
import {CommentDialogModule} from '@shared/modules/comment-dialog/comment-dialog.module';
|
||||||
import {FindigWidgetModule} from '@shared/widgets/findig-widget/findig-widget.module';
|
import {FindigWidgetModule} from '@shared/widgets/findig-widget/findig-widget.module';
|
||||||
|
import {TimerModule} from '@shared/modules/timer/timer.module';
|
||||||
|
|
||||||
@NgModule({
|
@NgModule({
|
||||||
declarations: [
|
declarations: [
|
||||||
|
@ -49,6 +50,8 @@ import {FindigWidgetModule} from '@shared/widgets/findig-widget/findig-widget.mo
|
||||||
FindingDialogModule,
|
FindingDialogModule,
|
||||||
CommentDialogModule,
|
CommentDialogModule,
|
||||||
FindigWidgetModule,
|
FindigWidgetModule,
|
||||||
|
// Modules
|
||||||
|
TimerModule,
|
||||||
]
|
]
|
||||||
})
|
})
|
||||||
export class PentestModule {
|
export class PentestModule {
|
||||||
|
|
|
@ -14,6 +14,7 @@
|
||||||
"action.download": "Herunterladen",
|
"action.download": "Herunterladen",
|
||||||
"action.report": "Bericht",
|
"action.report": "Bericht",
|
||||||
"action.reset": "Zurücksetzen",
|
"action.reset": "Zurücksetzen",
|
||||||
|
"action.complete": "Fertig",
|
||||||
"action.yes": "Ja",
|
"action.yes": "Ja",
|
||||||
"action.no": "Nein",
|
"action.no": "Nein",
|
||||||
"username": "Nutzername",
|
"username": "Nutzername",
|
||||||
|
@ -222,11 +223,14 @@
|
||||||
"not_started": "Nicht angefangen",
|
"not_started": "Nicht angefangen",
|
||||||
"disabled": "Deaktiviert",
|
"disabled": "Deaktiviert",
|
||||||
"open": "Offen",
|
"open": "Offen",
|
||||||
|
"paused": "Pausiert",
|
||||||
"in_progress": "In Bearbeitung",
|
"in_progress": "In Bearbeitung",
|
||||||
"completed": "Fertig"
|
"completed": "Fertig"
|
||||||
},
|
},
|
||||||
"popup": {
|
"popup": {
|
||||||
"not.found": "Keine pentests gefunden",
|
"not.found": "Keine pentests gefunden",
|
||||||
|
"initial.save.success": "Initialer Pentest erfolgreich aufgesetzt",
|
||||||
|
"initial.save.failed": "Initialer Pentest konnte nicht aufgesetzt werden",
|
||||||
"save.success": "Pentest erfolgreich gespeichert",
|
"save.success": "Pentest erfolgreich gespeichert",
|
||||||
"save.failed": "Pentest konnte nicht gespeichert werden",
|
"save.failed": "Pentest konnte nicht gespeichert werden",
|
||||||
"update.success": "Pentest erfolgreich aktualisiert",
|
"update.success": "Pentest erfolgreich aktualisiert",
|
||||||
|
|
|
@ -14,6 +14,7 @@
|
||||||
"action.download": "Download",
|
"action.download": "Download",
|
||||||
"action.report": "Report",
|
"action.report": "Report",
|
||||||
"action.reset": "Reset",
|
"action.reset": "Reset",
|
||||||
|
"action.complete": "Complete",
|
||||||
"action.yes": "Yes",
|
"action.yes": "Yes",
|
||||||
"action.no": "No",
|
"action.no": "No",
|
||||||
"username": "Username",
|
"username": "Username",
|
||||||
|
@ -222,11 +223,14 @@
|
||||||
"not_started": "Not Started",
|
"not_started": "Not Started",
|
||||||
"disabled": "Disabled",
|
"disabled": "Disabled",
|
||||||
"open": "Open",
|
"open": "Open",
|
||||||
|
"paused": "Paused",
|
||||||
"in_progress": "In progress",
|
"in_progress": "In progress",
|
||||||
"completed": "Completed"
|
"completed": "Completed"
|
||||||
},
|
},
|
||||||
"popup": {
|
"popup": {
|
||||||
"not.found": "No pentest found",
|
"not.found": "No pentest found",
|
||||||
|
"initial.save.success": "Initial Pentest successfully setup",
|
||||||
|
"initial.save.failed": "Initial Pentest could not be setup",
|
||||||
"save.success": "Pentest saved successfully",
|
"save.success": "Pentest saved successfully",
|
||||||
"save.failed": "Pentest could not be saved",
|
"save.failed": "Pentest could not be saved",
|
||||||
"update.success": "Pentest updated successfully",
|
"update.success": "Pentest updated successfully",
|
||||||
|
|
|
@ -4,16 +4,17 @@ export class Comment {
|
||||||
id?: string;
|
id?: string;
|
||||||
title: string;
|
title: string;
|
||||||
description?: string;
|
description?: string;
|
||||||
relatedFindings?: Array<string>;
|
// List of attachment id's for file upload
|
||||||
|
attachments?: Array<string>;
|
||||||
|
|
||||||
constructor(title: string,
|
constructor(title: string,
|
||||||
description: string,
|
description: string,
|
||||||
id?: string,
|
id?: string,
|
||||||
relatedFindings?: Array<string>) {
|
attachments?: Array<string>) {
|
||||||
this.id = id ? id : UUID();
|
this.id = id ? id : UUID();
|
||||||
this.title = title;
|
this.title = title;
|
||||||
this.description = description;
|
this.description = description;
|
||||||
this.relatedFindings = relatedFindings;
|
this.attachments = attachments;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -21,7 +22,7 @@ export interface CommentEntry {
|
||||||
commentId: string;
|
commentId: string;
|
||||||
title: string;
|
title: string;
|
||||||
description: string;
|
description: string;
|
||||||
relatedFindings: Array<string>;
|
attachments: Array<string>;
|
||||||
kind?: string;
|
kind?: string;
|
||||||
childEntries?: [];
|
childEntries?: [];
|
||||||
expanded?: boolean;
|
expanded?: boolean;
|
||||||
|
@ -34,7 +35,7 @@ export function transformCommentsToObjectiveEntries(findings: Comment[]): Commen
|
||||||
commentId: value.id,
|
commentId: value.id,
|
||||||
title: value.title,
|
title: value.title,
|
||||||
description: value.description,
|
description: value.description,
|
||||||
relatedFindings: value.relatedFindings,
|
attachments: value.attachments,
|
||||||
kind: 'cell',
|
kind: 'cell',
|
||||||
childEntries: null,
|
childEntries: null,
|
||||||
expanded: false
|
expanded: false
|
||||||
|
@ -48,8 +49,7 @@ export function transformCommentToRequestBody(comment: CommentDialogBody | Comme
|
||||||
...comment,
|
...comment,
|
||||||
title: comment.title,
|
title: comment.title,
|
||||||
description: comment.description,
|
description: comment.description,
|
||||||
// Transforms related findings from RelatedFindingOption to list of finding ids
|
attachments: comment.attachments,
|
||||||
relatedFindings: comment.relatedFindings ? comment.relatedFindings.map(finding => finding.id) : [],
|
|
||||||
/* Remove Table Entry Object Properties */
|
/* Remove Table Entry Object Properties */
|
||||||
childEntries: undefined,
|
childEntries: undefined,
|
||||||
kind: undefined,
|
kind: undefined,
|
||||||
|
@ -62,10 +62,6 @@ export function transformCommentToRequestBody(comment: CommentDialogBody | Comme
|
||||||
export interface CommentDialogBody {
|
export interface CommentDialogBody {
|
||||||
title: string;
|
title: string;
|
||||||
description: string;
|
description: string;
|
||||||
relatedFindings: Array<RelatedFindingOption>;
|
attachments: Array<string>;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface RelatedFindingOption {
|
|
||||||
id: string;
|
|
||||||
title: string;
|
|
||||||
}
|
|
||||||
|
|
|
@ -10,6 +10,8 @@ export class Finding {
|
||||||
affectedUrls?: Array<string>;
|
affectedUrls?: Array<string>;
|
||||||
reproduction: string;
|
reproduction: string;
|
||||||
mitigation?: string;
|
mitigation?: string;
|
||||||
|
// List of attachment id's for file upload
|
||||||
|
attachments?: Array<string>;
|
||||||
|
|
||||||
constructor(title: string,
|
constructor(title: string,
|
||||||
severity: Severity,
|
severity: Severity,
|
||||||
|
@ -18,7 +20,8 @@ export class Finding {
|
||||||
reproduction: string,
|
reproduction: string,
|
||||||
id?: string,
|
id?: string,
|
||||||
affectedUrls?: Array<string>,
|
affectedUrls?: Array<string>,
|
||||||
mitigation?: string) {
|
mitigation?: string,
|
||||||
|
attachments?: Array<string>) {
|
||||||
this.id = id ? id : UUID();
|
this.id = id ? id : UUID();
|
||||||
this.severity = severity;
|
this.severity = severity;
|
||||||
this.title = title;
|
this.title = title;
|
||||||
|
@ -27,13 +30,15 @@ export class Finding {
|
||||||
this.affectedUrls = affectedUrls ? affectedUrls : null;
|
this.affectedUrls = affectedUrls ? affectedUrls : null;
|
||||||
this.reproduction = reproduction;
|
this.reproduction = reproduction;
|
||||||
this.mitigation = mitigation ? mitigation : null;
|
this.mitigation = mitigation ? mitigation : null;
|
||||||
|
this.attachments = attachments ? attachments : null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface FindingEntry {
|
export interface FindingEntry {
|
||||||
findingId: string;
|
findingId: string;
|
||||||
severity: Severity;
|
|
||||||
title: string;
|
title: string;
|
||||||
|
severity: Severity;
|
||||||
|
description: string;
|
||||||
impact: string;
|
impact: string;
|
||||||
kind?: string;
|
kind?: string;
|
||||||
childEntries?: [];
|
childEntries?: [];
|
||||||
|
@ -45,8 +50,9 @@ export function transformFindingsToObjectiveEntries(findings: Finding[]): Findin
|
||||||
findings.forEach((value: Finding) => {
|
findings.forEach((value: Finding) => {
|
||||||
findingEntries.push({
|
findingEntries.push({
|
||||||
findingId: value.id,
|
findingId: value.id,
|
||||||
severity: typeof value.severity !== 'number' ? Severity[value.severity] : value.severity,
|
|
||||||
title: value.title,
|
title: value.title,
|
||||||
|
severity: typeof value.severity !== 'number' ? Severity[value.severity] : value.severity,
|
||||||
|
description: value.description,
|
||||||
impact: value.impact,
|
impact: value.impact,
|
||||||
kind: 'cell',
|
kind: 'cell',
|
||||||
childEntries: null,
|
childEntries: null,
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
export enum PentestStatus {
|
export enum PentestStatus {
|
||||||
NOT_STARTED = 'NOT_STARTED',
|
NOT_STARTED = 'NOT_STARTED',
|
||||||
DISABLED = 'DISABLED',
|
DISABLED = 'DISABLED',
|
||||||
OPEN = 'OPEN',
|
PAUSED = 'PAUSED',
|
||||||
IN_PROGRESS = 'IN_PROGRESS',
|
IN_PROGRESS = 'IN_PROGRESS',
|
||||||
COMPLETED = 'COMPLETED',
|
COMPLETED = 'COMPLETED',
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,6 +11,7 @@ export class Pentest {
|
||||||
status: PentestStatus;
|
status: PentestStatus;
|
||||||
findingIds?: Array<string>;
|
findingIds?: Array<string>;
|
||||||
commentIds?: Array<string>;
|
commentIds?: Array<string>;
|
||||||
|
timeSpent?: number;
|
||||||
|
|
||||||
constructor(category: Category,
|
constructor(category: Category,
|
||||||
refNumber: string,
|
refNumber: string,
|
||||||
|
@ -18,7 +19,8 @@ export class Pentest {
|
||||||
id?: string,
|
id?: string,
|
||||||
projectId?: string,
|
projectId?: string,
|
||||||
findingsIds?: Array<string>,
|
findingsIds?: Array<string>,
|
||||||
commentsIds?: Array<string>) {
|
commentsIds?: Array<string>,
|
||||||
|
timeSpent?: number) {
|
||||||
this.id = id ? id : UUID();
|
this.id = id ? id : UUID();
|
||||||
this.projectId = projectId ? projectId : '';
|
this.projectId = projectId ? projectId : '';
|
||||||
this.category = category;
|
this.category = category;
|
||||||
|
@ -26,6 +28,7 @@ export class Pentest {
|
||||||
this.status = status;
|
this.status = status;
|
||||||
this.findingIds = findingsIds ? findingsIds : [];
|
this.findingIds = findingsIds ? findingsIds : [];
|
||||||
this.commentIds = commentsIds ? commentsIds : [];
|
this.commentIds = commentsIds ? commentsIds : [];
|
||||||
|
this.timeSpent = timeSpent ? timeSpent : 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -50,25 +50,6 @@
|
||||||
</nb-form-field>
|
</nb-form-field>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<!-- Related Findings Layout -->
|
|
||||||
<!-- Related Findings Form Field -->
|
|
||||||
<nb-form-field class="comment-form-field">
|
|
||||||
<label for="{{formArray[2].fieldName}}" class="label">
|
|
||||||
{{formArray[2].labelKey | translate}}
|
|
||||||
</label>
|
|
||||||
<!--<fa-icon nbPrefix [icon]="fa.faExclamationCircle" size="lg" class="finding-icon"></fa-icon>-->
|
|
||||||
<nb-select placeholder="{{formArray[2].placeholder | translate}}"
|
|
||||||
id="{{formArray[2].fieldName}}"
|
|
||||||
formControlName="{{formArray[2].fieldName}}"
|
|
||||||
(selectedChange)="changeSelected($event)"
|
|
||||||
multiple fullWidth shape="semi-round" filled status="info"
|
|
||||||
[size]="'large'" class="form-field relatedFindings">
|
|
||||||
<nb-option class="reset-option">{{'global.action.reset' | translate}}</nb-option>
|
|
||||||
<nb-option class="finding-option" *ngFor="let finding of relatedFindings" [value]="finding">
|
|
||||||
{{finding.title}}
|
|
||||||
</nb-option>
|
|
||||||
</nb-select>
|
|
||||||
</nb-form-field>
|
|
||||||
</form>
|
</form>
|
||||||
</nb-card-body>
|
</nb-card-body>
|
||||||
<nb-card-footer fxLayout="row" fxLayoutGap="1.5rem" fxLayoutAlign="end end">
|
<nb-card-footer fxLayout="row" fxLayoutGap="1.5rem" fxLayoutAlign="end end">
|
||||||
|
|
|
@ -31,7 +31,8 @@
|
||||||
|
|
||||||
.form-textarea {
|
.form-textarea {
|
||||||
width: 42rem !important;
|
width: 42rem !important;
|
||||||
height: 8rem;
|
// Change back to 16rem after attachments can be uploaded
|
||||||
|
height: 24rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
.comment-form-field {
|
.comment-form-field {
|
||||||
|
|
|
@ -5,7 +5,6 @@ import * as FA from '@fortawesome/free-solid-svg-icons';
|
||||||
import deepEqual from 'deep-equal';
|
import deepEqual from 'deep-equal';
|
||||||
import {NB_DIALOG_CONFIG, NbDialogRef} from '@nebular/theme';
|
import {NB_DIALOG_CONFIG, NbDialogRef} from '@nebular/theme';
|
||||||
import {UntilDestroy} from '@ngneat/until-destroy';
|
import {UntilDestroy} from '@ngneat/until-destroy';
|
||||||
import {RelatedFindingOption} from '@shared/models/comment.model';
|
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-comment-dialog',
|
selector: 'app-comment-dialog',
|
||||||
|
@ -24,11 +23,6 @@ export class CommentDialogComponent implements OnInit {
|
||||||
// HTML only
|
// HTML only
|
||||||
readonly fa = FA;
|
readonly fa = FA;
|
||||||
|
|
||||||
relatedFindings: RelatedFindingOption[] = [];
|
|
||||||
// Includes the findings that got selected as an option
|
|
||||||
selectedFindings: RelatedFindingOption[] = [];
|
|
||||||
initialSelectedFindings: RelatedFindingOption[] = [];
|
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
@Inject(NB_DIALOG_CONFIG) private data: GenericDialogData,
|
@Inject(NB_DIALOG_CONFIG) private data: GenericDialogData,
|
||||||
private fb: FormBuilder,
|
private fb: FormBuilder,
|
||||||
|
@ -38,7 +32,6 @@ export class CommentDialogComponent implements OnInit {
|
||||||
|
|
||||||
ngOnInit(): void {
|
ngOnInit(): void {
|
||||||
this.dialogData = this.data;
|
this.dialogData = this.data;
|
||||||
this.relatedFindings = this.dialogData.options[0].additionalData;
|
|
||||||
this.commentFormGroup = this.generateFormCreationFieldArray();
|
this.commentFormGroup = this.generateFormCreationFieldArray();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -48,29 +41,19 @@ export class CommentDialogComponent implements OnInit {
|
||||||
...accumulator,
|
...accumulator,
|
||||||
[currentValue?.fieldName]: currentValue?.controlsConfig
|
[currentValue?.fieldName]: currentValue?.controlsConfig
|
||||||
}), {});
|
}), {});
|
||||||
// tslint:disable-next-line:no-string-literal
|
|
||||||
const preSelectedRelatedFindings = this.data.form['commentRelatedFindings'].controlsConfig[0].value;
|
|
||||||
if (preSelectedRelatedFindings && preSelectedRelatedFindings.length > 0) {
|
|
||||||
this.relatedFindings.forEach(finding => {
|
|
||||||
if (preSelectedRelatedFindings.includes(finding)) {
|
|
||||||
this.initialSelectedFindings.push(finding);
|
|
||||||
this.selectedFindings.push(finding);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
return this.fb.group(config);
|
return this.fb.group(config);
|
||||||
}
|
}
|
||||||
|
|
||||||
changeSelected($event): void {
|
changeAttachments($event): void {
|
||||||
// tslint:disable-next-line:no-string-literal
|
// tslint:disable-next-line:no-string-literal
|
||||||
this.selectedFindings = this.commentFormGroup.controls['commentRelatedFindings'].value;
|
// this.commentFormGroup.controls['commentAttachments'].value;
|
||||||
}
|
}
|
||||||
|
|
||||||
onClickSave(value: any): void {
|
onClickSave(value: any): void {
|
||||||
this.dialogRef.close({
|
this.dialogRef.close({
|
||||||
title: value.commentTitle,
|
title: value.commentTitle,
|
||||||
description: value.commentDescription,
|
description: value.commentDescription,
|
||||||
relatedFindings: this.selectedFindings ? this.selectedFindings : []
|
// relatedFindings: this.selectedFindings ? this.selectedFindings : []
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -90,12 +73,8 @@ export class CommentDialogComponent implements OnInit {
|
||||||
const newCommentData = this.commentFormGroup.getRawValue();
|
const newCommentData = this.commentFormGroup.getRawValue();
|
||||||
Object.entries(newCommentData).forEach(entry => {
|
Object.entries(newCommentData).forEach(entry => {
|
||||||
const [key, value] = entry;
|
const [key, value] = entry;
|
||||||
// Related Findings form field can be ignored since changes here will be recognised inside commentRelatedFindings of tag-list
|
|
||||||
if (value === null || key === 'commentRelatedFindings') {
|
|
||||||
newCommentData[key] = '';
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
const didChange = !deepEqual(oldCommentData, newCommentData) || !deepEqual(this.initialSelectedFindings, this.selectedFindings);
|
const didChange = !deepEqual(oldCommentData, newCommentData);
|
||||||
return didChange;
|
return didChange;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -109,10 +88,6 @@ export class CommentDialogComponent implements OnInit {
|
||||||
const [key, value] = entry;
|
const [key, value] = entry;
|
||||||
commentData[key] = value.controlsConfig[0] ?
|
commentData[key] = value.controlsConfig[0] ?
|
||||||
(value.controlsConfig[0].value ? value.controlsConfig[0].value : value.controlsConfig[0]) : '';
|
(value.controlsConfig[0].value ? value.controlsConfig[0].value : value.controlsConfig[0]) : '';
|
||||||
// Related Findings form field can be ignored since changes here will be recognised inside commentRelatedFindings of tag-list
|
|
||||||
if (key === 'commentRelatedFindings') {
|
|
||||||
commentData[key] = '';
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
return commentData;
|
return commentData;
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,7 +5,7 @@ import {ComponentType} from '@angular/cdk/overlay';
|
||||||
import {Observable} from 'rxjs';
|
import {Observable} from 'rxjs';
|
||||||
import {Validators} from '@angular/forms';
|
import {Validators} from '@angular/forms';
|
||||||
import {CommentDialogComponent} from '@shared/modules/comment-dialog/comment-dialog.component';
|
import {CommentDialogComponent} from '@shared/modules/comment-dialog/comment-dialog.component';
|
||||||
import {Comment, RelatedFindingOption} from '@shared/models/comment.model';
|
import {Comment} from '@shared/models/comment.model';
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class CommentDialogService {
|
export class CommentDialogService {
|
||||||
|
@ -30,18 +30,15 @@ export class CommentDialogService {
|
||||||
|
|
||||||
public openCommentDialog(componentOrTemplateRef: ComponentType<any>,
|
public openCommentDialog(componentOrTemplateRef: ComponentType<any>,
|
||||||
findingIds: string[],
|
findingIds: string[],
|
||||||
relatedFindings: RelatedFindingOption[],
|
|
||||||
comment?: Comment,
|
comment?: Comment,
|
||||||
config?: Partial<NbDialogConfig<Partial<any> | string>>): Observable<any> {
|
config?: Partial<NbDialogConfig<Partial<any> | string>>): Observable<any> {
|
||||||
let dialogOptions: Partial<NbDialogConfig<Partial<any> | string>>;
|
let dialogOptions: Partial<NbDialogConfig<Partial<any> | string>>;
|
||||||
let dialogData: GenericDialogData;
|
let dialogData: GenericDialogData;
|
||||||
// Preselect related findings
|
// Preselect attachments
|
||||||
const selectedRelatedFindings: RelatedFindingOption[] = [];
|
const attachments: string[] = [];
|
||||||
if (comment && comment.relatedFindings.length > 0 && relatedFindings) {
|
if (comment && comment.attachments.length > 0) {
|
||||||
relatedFindings.forEach(finding => {
|
comment.attachments.forEach(attachment => {
|
||||||
if (comment.relatedFindings.includes(finding.id)) {
|
// Load attachment to show
|
||||||
selectedRelatedFindings.push(finding);
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
// Setup CommentDialogBody
|
// Setup CommentDialogBody
|
||||||
|
@ -72,22 +69,6 @@ export class CommentDialogService {
|
||||||
errors: [
|
errors: [
|
||||||
{errorCode: 'required', translationKey: 'comment.validationMessage.descriptionRequired'}
|
{errorCode: 'required', translationKey: 'comment.validationMessage.descriptionRequired'}
|
||||||
]
|
]
|
||||||
},
|
|
||||||
commentRelatedFindings: {
|
|
||||||
fieldName: 'commentRelatedFindings',
|
|
||||||
type: 'text',
|
|
||||||
labelKey: 'comment.relatedFindings.label',
|
|
||||||
placeholder: findingIds.length === 0 ? 'comment.noFindingsInObjectivePlaceholder' : 'comment.relatedFindingsPlaceholder',
|
|
||||||
controlsConfig: [
|
|
||||||
{
|
|
||||||
value: comment ? selectedRelatedFindings : [],
|
|
||||||
disabled: findingIds.length === 0
|
|
||||||
},
|
|
||||||
[]
|
|
||||||
],
|
|
||||||
errors: [
|
|
||||||
{errorCode: 'required', translationKey: 'finding.validationMessage.relatedFindings'}
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
options: []
|
options: []
|
||||||
|
@ -97,8 +78,7 @@ export class CommentDialogService {
|
||||||
{
|
{
|
||||||
headerLabelKey: 'comment.edit.header',
|
headerLabelKey: 'comment.edit.header',
|
||||||
buttonKey: 'global.action.update',
|
buttonKey: 'global.action.update',
|
||||||
accentColor: 'warning',
|
accentColor: 'warning'
|
||||||
additionalData: relatedFindings
|
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
} else {
|
} else {
|
||||||
|
@ -106,8 +86,7 @@ export class CommentDialogService {
|
||||||
{
|
{
|
||||||
headerLabelKey: 'comment.create.header',
|
headerLabelKey: 'comment.create.header',
|
||||||
buttonKey: 'global.action.save',
|
buttonKey: 'global.action.save',
|
||||||
accentColor: 'info',
|
accentColor: 'info'
|
||||||
additionalData: relatedFindings
|
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
import {ComponentFixture, TestBed} from '@angular/core/testing';
|
import {ComponentFixture, TestBed} from '@angular/core/testing';
|
||||||
|
|
||||||
import {ExportReportDialogComponent} from './export-report-dialog.component';
|
import {ExportReportDialogComponent} from './export-report-dialog.component';
|
||||||
import {CommonModule} from '@angular/common';
|
|
||||||
import {
|
import {
|
||||||
NB_DIALOG_CONFIG,
|
NB_DIALOG_CONFIG,
|
||||||
NbButtonModule,
|
NbButtonModule,
|
||||||
|
@ -9,11 +8,10 @@ import {
|
||||||
NbDialogRef,
|
NbDialogRef,
|
||||||
NbFormFieldModule,
|
NbFormFieldModule,
|
||||||
NbInputModule,
|
NbInputModule,
|
||||||
NbLayoutModule, NbRadioModule,
|
NbRadioModule
|
||||||
NbTagModule
|
|
||||||
} from '@nebular/theme';
|
} from '@nebular/theme';
|
||||||
import {FlexLayoutModule} from '@angular/flex-layout';
|
import {FlexLayoutModule} from '@angular/flex-layout';
|
||||||
import {NG_VALUE_ACCESSOR, ReactiveFormsModule} from '@angular/forms';
|
import {ReactiveFormsModule} from '@angular/forms';
|
||||||
import {BrowserAnimationsModule} from '@angular/platform-browser/animations';
|
import {BrowserAnimationsModule} from '@angular/platform-browser/animations';
|
||||||
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';
|
||||||
|
@ -29,7 +27,6 @@ import {createSpyObj} from '@shared/modules/finding-dialog/finding-dialog.compon
|
||||||
import {Project, ProjectPentests} from '@shared/models/project.model';
|
import {Project, ProjectPentests} from '@shared/models/project.model';
|
||||||
import {PentestStatus} from '@shared/models/pentest-status.model';
|
import {PentestStatus} from '@shared/models/pentest-status.model';
|
||||||
import {ObjectiveChartModule} from '@shared/modules/objective-chart/objective-chart.module';
|
import {ObjectiveChartModule} from '@shared/modules/objective-chart/objective-chart.module';
|
||||||
import {forwardRef} from '@angular/core';
|
|
||||||
import {FontAwesomeModule} from '@fortawesome/angular-fontawesome';
|
import {FontAwesomeModule} from '@fortawesome/angular-fontawesome';
|
||||||
|
|
||||||
describe('ExportReportDialogComponent', () => {
|
describe('ExportReportDialogComponent', () => {
|
||||||
|
|
|
@ -41,7 +41,7 @@ export class ObjectiveChartComponent implements OnInit {
|
||||||
readonly pentestStatusLabels: Array<string> = [
|
readonly pentestStatusLabels: Array<string> = [
|
||||||
'pentest.statusText.disabled',
|
'pentest.statusText.disabled',
|
||||||
'pentest.statusText.not_started',
|
'pentest.statusText.not_started',
|
||||||
'pentest.statusText.open',
|
'pentest.statusText.paused',
|
||||||
'pentest.statusText.in_progress',
|
'pentest.statusText.in_progress',
|
||||||
'pentest.statusText.completed'
|
'pentest.statusText.completed'
|
||||||
];
|
];
|
||||||
|
@ -58,7 +58,7 @@ export class ObjectiveChartComponent implements OnInit {
|
||||||
const disabledPentests: ProjectPentests[]
|
const disabledPentests: ProjectPentests[]
|
||||||
= this.projectPentestData.filter(projectPentest => projectPentest.status === PentestStatus.DISABLED);
|
= this.projectPentestData.filter(projectPentest => projectPentest.status === PentestStatus.DISABLED);
|
||||||
const openPentests: ProjectPentests[]
|
const openPentests: ProjectPentests[]
|
||||||
= this.projectPentestData.filter(projectPentest => projectPentest.status === PentestStatus.OPEN);
|
= this.projectPentestData.filter(projectPentest => projectPentest.status === PentestStatus.PAUSED);
|
||||||
const inProgressPentests: ProjectPentests[]
|
const inProgressPentests: ProjectPentests[]
|
||||||
= this.projectPentestData.filter(projectPentest => projectPentest.status === PentestStatus.IN_PROGRESS);
|
= this.projectPentestData.filter(projectPentest => projectPentest.status === PentestStatus.IN_PROGRESS);
|
||||||
const completedPentests: ProjectPentests[]
|
const completedPentests: ProjectPentests[]
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
|
|
||||||
.project-dialog {
|
.project-dialog {
|
||||||
width: 34rem !important;
|
width: 34rem !important;
|
||||||
height: 42.5rem;
|
height: 43.5rem;
|
||||||
|
|
||||||
.project-dialog-header {
|
.project-dialog-header {
|
||||||
height: 8vh;
|
height: 8vh;
|
||||||
|
|
|
@ -0,0 +1,16 @@
|
||||||
|
import { TestBed } from '@angular/core/testing';
|
||||||
|
|
||||||
|
import { TimerService } from './timer.service';
|
||||||
|
|
||||||
|
describe('TimerService', () => {
|
||||||
|
let service: TimerService;
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
TestBed.configureTestingModule({});
|
||||||
|
service = TestBed.inject(TimerService);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should be created', () => {
|
||||||
|
expect(service).toBeTruthy();
|
||||||
|
});
|
||||||
|
});
|
|
@ -0,0 +1,9 @@
|
||||||
|
import { Injectable } from '@angular/core';
|
||||||
|
|
||||||
|
@Injectable({
|
||||||
|
providedIn: 'root'
|
||||||
|
})
|
||||||
|
export class TimerService {
|
||||||
|
|
||||||
|
constructor() { }
|
||||||
|
}
|
|
@ -0,0 +1,18 @@
|
||||||
|
<div class="timer-module" fxLayout="row" fxLayoutGap="0.5rem" fxLayoutAlign="end center">
|
||||||
|
<div class="time">
|
||||||
|
<fa-icon [icon]="fa.faStopwatch" class="stopwatch-icon fa-xl"></fa-icon>
|
||||||
|
<span>{{ timer | timerDuration }}</span>
|
||||||
|
</div>
|
||||||
|
<!-- status="{{getStopwatchButtonStatus()}}" -->
|
||||||
|
<button nbButton outline
|
||||||
|
shape="semi-round"
|
||||||
|
status="{{timerRunning$.getValue() === true ? 'warning' : 'info'}}"
|
||||||
|
class="stopwatch-player-button"
|
||||||
|
(click)="onClickTriggerTimer()">
|
||||||
|
<fa-icon *ngIf="timerRunning$.getValue(), else changeTimerIcon" [icon]="fa.faPause"
|
||||||
|
class="new-element-icon"></fa-icon>
|
||||||
|
<ng-template #changeTimerIcon>
|
||||||
|
<fa-icon [icon]="fa.faPlay" class="stopwatch-player-icon"></fa-icon>
|
||||||
|
</ng-template>
|
||||||
|
</button>
|
||||||
|
</div>
|
|
@ -0,0 +1,28 @@
|
||||||
|
@import '../../../assets/@theme/styles/themes';
|
||||||
|
|
||||||
|
.timer-module {
|
||||||
|
width: 12rem;
|
||||||
|
max-width: 12rem;
|
||||||
|
|
||||||
|
// height: 3rem;
|
||||||
|
// max-height: 3rem;
|
||||||
|
|
||||||
|
// overflow: auto;
|
||||||
|
|
||||||
|
background-color: nb-theme(color-basic-transparent-focus);
|
||||||
|
border-radius: 10px;
|
||||||
|
|
||||||
|
|
||||||
|
.time {
|
||||||
|
//font-family: Courier, serif;
|
||||||
|
|
||||||
|
.stopwatch-icon {
|
||||||
|
padding-right: 1.5rem;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.stopwatch-player-button {
|
||||||
|
margin-left: 1rem;
|
||||||
|
width: 3.25rem !important;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,54 @@
|
||||||
|
import {ComponentFixture, TestBed} from '@angular/core/testing';
|
||||||
|
|
||||||
|
import {TimerComponent} from './timer.component';
|
||||||
|
import {MockPipe} from 'ng-mocks';
|
||||||
|
import {TimerDurationPipe} from '@shared/pipes/timer-duration.pipe';
|
||||||
|
import {TranslateLoader, TranslateModule} from '@ngx-translate/core';
|
||||||
|
import {HttpLoaderFactory} from '../../../app/common-app.module';
|
||||||
|
import {HttpClient, HttpClientModule} from '@angular/common/http';
|
||||||
|
import {HttpClientTestingModule} from '@angular/common/http/testing';
|
||||||
|
import {CommonModule} from '@angular/common';
|
||||||
|
import {NotificationService} from '@shared/services/toaster-service/notification.service';
|
||||||
|
import {NotificationServiceMock} from '@shared/services/toaster-service/notification.service.mock';
|
||||||
|
import {NgxsModule} from '@ngxs/store';
|
||||||
|
|
||||||
|
describe('TimerComponent', () => {
|
||||||
|
let component: TimerComponent;
|
||||||
|
let fixture: ComponentFixture<TimerComponent>;
|
||||||
|
|
||||||
|
beforeEach(async () => {
|
||||||
|
await TestBed.configureTestingModule({
|
||||||
|
declarations: [
|
||||||
|
TimerComponent,
|
||||||
|
MockPipe(TimerDurationPipe)
|
||||||
|
],
|
||||||
|
imports: [
|
||||||
|
CommonModule,
|
||||||
|
TranslateModule.forRoot({
|
||||||
|
loader: {
|
||||||
|
provide: TranslateLoader,
|
||||||
|
useFactory: HttpLoaderFactory,
|
||||||
|
deps: [HttpClient]
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
NgxsModule.forRoot([]),
|
||||||
|
HttpClientModule,
|
||||||
|
HttpClientTestingModule
|
||||||
|
],
|
||||||
|
providers: [
|
||||||
|
{provide: NotificationService, useValue: new NotificationServiceMock()}
|
||||||
|
]
|
||||||
|
})
|
||||||
|
.compileComponents();
|
||||||
|
});
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
fixture = TestBed.createComponent(TimerComponent);
|
||||||
|
component = fixture.componentInstance;
|
||||||
|
fixture.detectChanges();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should create', () => {
|
||||||
|
expect(component).toBeTruthy();
|
||||||
|
});
|
||||||
|
});
|
|
@ -0,0 +1,142 @@
|
||||||
|
import {ChangeDetectionStrategy, Component, OnDestroy, OnInit} from '@angular/core';
|
||||||
|
import * as FA from '@fortawesome/free-solid-svg-icons';
|
||||||
|
import {BehaviorSubject} from 'rxjs';
|
||||||
|
import {PentestStatus} from '@shared/models/pentest-status.model';
|
||||||
|
import {Store} from '@ngxs/store';
|
||||||
|
import {ProjectState} from '@shared/stores/project-state/project-state';
|
||||||
|
import {UntilDestroy, untilDestroyed} from '@ngneat/until-destroy';
|
||||||
|
import {Pentest, transformPentestToRequestBody} from '@shared/models/pentest.model';
|
||||||
|
import {ChangePentest, UpdatePentestStatus, UpdatePentestTime} from '@shared/stores/project-state/project-state.actions';
|
||||||
|
import {NotificationService, PopupType} from '@shared/services/toaster-service/notification.service';
|
||||||
|
import {PentestService} from '@shared/services/api/pentest.service';
|
||||||
|
import {Project} from '@shared/models/project.model';
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'app-timer',
|
||||||
|
templateUrl: './timer.component.html',
|
||||||
|
styleUrls: ['./timer.component.scss'],
|
||||||
|
changeDetection: ChangeDetectionStrategy.Default
|
||||||
|
})
|
||||||
|
@UntilDestroy()
|
||||||
|
export class TimerComponent implements OnInit, OnDestroy {
|
||||||
|
|
||||||
|
readonly fa = FA;
|
||||||
|
|
||||||
|
timer = 0;
|
||||||
|
interval;
|
||||||
|
|
||||||
|
pentestInfo$: BehaviorSubject<Pentest> = new BehaviorSubject<Pentest>(null);
|
||||||
|
timerRunning$: BehaviorSubject<boolean> = new BehaviorSubject<boolean>(false);
|
||||||
|
// Needed for initial pentest creation
|
||||||
|
selectedProjectId$: BehaviorSubject<string> = new BehaviorSubject<string>('');
|
||||||
|
|
||||||
|
constructor(private pentestService: PentestService,
|
||||||
|
private notificationService: NotificationService,
|
||||||
|
private readonly store: Store) {
|
||||||
|
}
|
||||||
|
|
||||||
|
ngOnInit(): void {
|
||||||
|
this.store.selectOnce(ProjectState.project).pipe(
|
||||||
|
untilDestroyed(this)
|
||||||
|
).subscribe({
|
||||||
|
next: (selectedProject: Project) => {
|
||||||
|
this.selectedProjectId$.next(selectedProject.id);
|
||||||
|
},
|
||||||
|
error: err => {
|
||||||
|
console.error(err);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
this.store.selectOnce(ProjectState.pentest).pipe(
|
||||||
|
untilDestroyed(this)
|
||||||
|
).subscribe({
|
||||||
|
next: (selectedPentest: Pentest) => {
|
||||||
|
this.pentestInfo$.next(selectedPentest);
|
||||||
|
// In case pentest time spent is undefined use 0
|
||||||
|
this.timer = selectedPentest.timeSpent ? selectedPentest.timeSpent : 0;
|
||||||
|
if (!selectedPentest.id) {
|
||||||
|
this.createIntialPentestInBackend();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
error: err => {
|
||||||
|
console.error(err);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private createIntialPentestInBackend(): void {
|
||||||
|
// Save initial Pentest a new
|
||||||
|
this.pentestInfo$.next({...this.pentestInfo$.getValue(), timeSpent: this.timer});
|
||||||
|
this.pentestService.savePentest(this.selectedProjectId$.getValue(), transformPentestToRequestBody(this.pentestInfo$.getValue()))
|
||||||
|
.subscribe({
|
||||||
|
next: (pentest: Pentest) => {
|
||||||
|
this.store.dispatch(new ChangePentest(pentest));
|
||||||
|
this.notificationService.showPopup('pentest.popup.initial.save.success', PopupType.SUCCESS);
|
||||||
|
},
|
||||||
|
error: err => {
|
||||||
|
console.log(err);
|
||||||
|
this.notificationService.showPopup('pentest.popup.initial.save.failed', PopupType.FAILURE);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
onClickTriggerTimer(): void {
|
||||||
|
this.timerRunning$.next(!this.timerRunning$.getValue());
|
||||||
|
// Start or pause timer
|
||||||
|
if (this.timerRunning$.getValue()) {
|
||||||
|
this.startTimer();
|
||||||
|
} else {
|
||||||
|
this.pauseTimer();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// TIMER related functions below
|
||||||
|
private startTimer(): boolean {
|
||||||
|
this.interval = setInterval(() => this.timer++, 1000);
|
||||||
|
this.store.dispatch(new UpdatePentestStatus(PentestStatus.IN_PROGRESS));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private pauseTimer(): boolean {
|
||||||
|
clearInterval(this.interval);
|
||||||
|
this.store.dispatch(new UpdatePentestTime(this.timer));
|
||||||
|
this.store.dispatch(new UpdatePentestStatus(PentestStatus.PAUSED));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the correct nb-status for current pentest-status
|
||||||
|
*/
|
||||||
|
getStopwatchButtonStatus(): string {
|
||||||
|
const value: PentestStatus = this.pentestInfo$.getValue().status;
|
||||||
|
let stopwatchButtonStatus;
|
||||||
|
switch (value) {
|
||||||
|
case PentestStatus.NOT_STARTED: {
|
||||||
|
stopwatchButtonStatus = 'basic';
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case PentestStatus.PAUSED: {
|
||||||
|
stopwatchButtonStatus = 'info';
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case PentestStatus.IN_PROGRESS: {
|
||||||
|
stopwatchButtonStatus = 'warning';
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case PentestStatus.COMPLETED: {
|
||||||
|
stopwatchButtonStatus = 'success';
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default: {
|
||||||
|
stopwatchButtonStatus = 'basic';
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return stopwatchButtonStatus;
|
||||||
|
}
|
||||||
|
|
||||||
|
ngOnDestroy(): void {
|
||||||
|
// Automatically push new time spent to store
|
||||||
|
this.store.dispatch(new UpdatePentestTime(this.timer));
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,29 @@
|
||||||
|
import { NgModule } from '@angular/core';
|
||||||
|
import { CommonModule } from '@angular/common';
|
||||||
|
import {TimerComponent} from '@shared/modules/timer/timer.component';
|
||||||
|
import {TimerService} from '@shared/modules/timer/service/timer.service';
|
||||||
|
import {NbButtonModule, NbCardModule} from '@nebular/theme';
|
||||||
|
import {FlexLayoutModule} from '@angular/flex-layout';
|
||||||
|
import {FontAwesomeModule} from '@fortawesome/angular-fontawesome';
|
||||||
|
import {TimerDurationPipe} from '@shared/pipes/timer-duration.pipe';
|
||||||
|
|
||||||
|
@NgModule({
|
||||||
|
declarations: [
|
||||||
|
TimerComponent,
|
||||||
|
TimerDurationPipe
|
||||||
|
],
|
||||||
|
imports: [
|
||||||
|
CommonModule,
|
||||||
|
NbCardModule,
|
||||||
|
FlexLayoutModule,
|
||||||
|
FontAwesomeModule,
|
||||||
|
NbButtonModule
|
||||||
|
],
|
||||||
|
providers: [
|
||||||
|
TimerService
|
||||||
|
],
|
||||||
|
exports: [
|
||||||
|
TimerComponent
|
||||||
|
]
|
||||||
|
})
|
||||||
|
export class TimerModule { }
|
|
@ -0,0 +1,8 @@
|
||||||
|
import { TimerDurationPipe } from './timer-duration.pipe';
|
||||||
|
|
||||||
|
describe('TimerDurationPipe', () => {
|
||||||
|
it('create an instance', () => {
|
||||||
|
const pipe = new TimerDurationPipe();
|
||||||
|
expect(pipe).toBeTruthy();
|
||||||
|
});
|
||||||
|
});
|
|
@ -0,0 +1,38 @@
|
||||||
|
import {Pipe, PipeTransform} from '@angular/core';
|
||||||
|
|
||||||
|
@Pipe({
|
||||||
|
name: 'timerDuration',
|
||||||
|
pure: false
|
||||||
|
})
|
||||||
|
export class TimerDurationPipe implements PipeTransform {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Transforms input time into readable time indication
|
||||||
|
* @param time of type number
|
||||||
|
* @param args The unit to be used for calculation
|
||||||
|
* @returns string in the format `HH:mm:ss`
|
||||||
|
*/
|
||||||
|
transform(time: any, ...args: any[]): string {
|
||||||
|
let hours: string | number = 0;
|
||||||
|
let minutes: string | number = 0;
|
||||||
|
let seconds: string | number = 0;
|
||||||
|
if (time) {
|
||||||
|
// tslint:disable-next-line:variable-name
|
||||||
|
const sec_num = parseInt(time, 10); // don't forget the second param
|
||||||
|
hours = Math.floor(sec_num / 3600);
|
||||||
|
minutes = Math.floor((sec_num - (hours * 3600)) / 60);
|
||||||
|
seconds = sec_num - (hours * 3600) - (minutes * 60);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add the relevant `0` prefix if any of the numbers are less than 10
|
||||||
|
* i.e. 5 -> 05
|
||||||
|
*/
|
||||||
|
seconds = (seconds < 10) ? '0' + seconds : seconds;
|
||||||
|
minutes = (minutes < 10) ? '0' + minutes : minutes;
|
||||||
|
hours = (hours < 10) ? '0' + hours : hours;
|
||||||
|
// Return time in as string in `HH:mm:ss` format
|
||||||
|
return `${hours}:${minutes}:${seconds}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -1,6 +1,7 @@
|
||||||
import {Project} from '@shared/models/project.model';
|
import {Project} from '@shared/models/project.model';
|
||||||
import {Category} from '@shared/models/category.model';
|
import {Category} from '@shared/models/category.model';
|
||||||
import {Pentest} from '@shared/models/pentest.model';
|
import {Pentest} from '@shared/models/pentest.model';
|
||||||
|
import {PentestStatus} from '@shared/models/pentest-status.model';
|
||||||
|
|
||||||
|
|
||||||
export class InitProjectState {
|
export class InitProjectState {
|
||||||
|
@ -34,6 +35,20 @@ export class ChangePentest {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export class UpdatePentestStatus {
|
||||||
|
static readonly type = '[ProjectState] UpdatePentestStatus';
|
||||||
|
|
||||||
|
constructor(public newPentestStatus: PentestStatus) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export class UpdatePentestTime {
|
||||||
|
static readonly type = '[ProjectState] UpdatePentestTime';
|
||||||
|
|
||||||
|
constructor(public time: number) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
export class UpdatePentestFindings {
|
export class UpdatePentestFindings {
|
||||||
static readonly type = '[ProjectState] UpdatePentestFindings';
|
static readonly type = '[ProjectState] UpdatePentestFindings';
|
||||||
|
|
||||||
|
|
|
@ -5,11 +5,14 @@ import {
|
||||||
ChangeCategory,
|
ChangeCategory,
|
||||||
ChangePentest,
|
ChangePentest,
|
||||||
ChangeProject,
|
ChangeProject,
|
||||||
InitProjectState, UpdatePentestComments,
|
InitProjectState,
|
||||||
UpdatePentestFindings
|
UpdatePentestComments,
|
||||||
|
UpdatePentestFindings, UpdatePentestStatus,
|
||||||
|
UpdatePentestTime
|
||||||
} from '@shared/stores/project-state/project-state.actions';
|
} from '@shared/stores/project-state/project-state.actions';
|
||||||
import {Category} from '@shared/models/category.model';
|
import {Category} from '@shared/models/category.model';
|
||||||
import {Pentest} from '@shared/models/pentest.model';
|
import {Pentest} from '@shared/models/pentest.model';
|
||||||
|
import {PentestStatus} from '@shared/models/pentest-status.model';
|
||||||
|
|
||||||
export const PROJECT_STATE_NAME = 'project';
|
export const PROJECT_STATE_NAME = 'project';
|
||||||
|
|
||||||
|
@ -91,6 +94,40 @@ export class ProjectState {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Action(UpdatePentestStatus)
|
||||||
|
updatePentestStatus(ctx: StateContext<ProjectStateModel>, {newPentestStatus}: UpdatePentestStatus): void {
|
||||||
|
const state = ctx.getState();
|
||||||
|
let stateSelectedPentest: Pentest = state.selectedPentest;
|
||||||
|
// State object
|
||||||
|
const statePentestStatus: PentestStatus = stateSelectedPentest.status || PentestStatus.NOT_STARTED;
|
||||||
|
// overwrites only timeSpent
|
||||||
|
stateSelectedPentest = {
|
||||||
|
...stateSelectedPentest,
|
||||||
|
status: newPentestStatus
|
||||||
|
};
|
||||||
|
// patch project state
|
||||||
|
ctx.patchState({
|
||||||
|
selectedPentest: stateSelectedPentest
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@Action(UpdatePentestTime)
|
||||||
|
updatePentestTime(ctx: StateContext<ProjectStateModel>, {time}: UpdatePentestTime): void {
|
||||||
|
const state = ctx.getState();
|
||||||
|
let stateSelectedPentest: Pentest = state.selectedPentest;
|
||||||
|
// State object
|
||||||
|
const statePentestTimeSpent: number = stateSelectedPentest.timeSpent || 0;
|
||||||
|
// overwrites only timeSpent
|
||||||
|
stateSelectedPentest = {
|
||||||
|
...stateSelectedPentest,
|
||||||
|
timeSpent: time
|
||||||
|
};
|
||||||
|
// patch project state
|
||||||
|
ctx.patchState({
|
||||||
|
selectedPentest: stateSelectedPentest
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
@Action(UpdatePentestFindings)
|
@Action(UpdatePentestFindings)
|
||||||
updatePentestFindings(ctx: StateContext<ProjectStateModel>, {findingId}: UpdatePentestFindings): void {
|
updatePentestFindings(ctx: StateContext<ProjectStateModel>, {findingId}: UpdatePentestFindings): void {
|
||||||
const state = ctx.getState();
|
const state = ctx.getState();
|
||||||
|
@ -109,7 +146,7 @@ export class ProjectState {
|
||||||
...stateSelectedPentest,
|
...stateSelectedPentest,
|
||||||
findingIds: updatedFindingIds
|
findingIds: updatedFindingIds
|
||||||
};
|
};
|
||||||
// path project state
|
// patch project state
|
||||||
ctx.patchState({
|
ctx.patchState({
|
||||||
selectedPentest: stateSelectedPentest
|
selectedPentest: stateSelectedPentest
|
||||||
});
|
});
|
||||||
|
@ -133,7 +170,7 @@ export class ProjectState {
|
||||||
...stateSelectedPentest,
|
...stateSelectedPentest,
|
||||||
commentIds: updatedCommentIds
|
commentIds: updatedCommentIds
|
||||||
};
|
};
|
||||||
// path project state
|
// patch project state
|
||||||
ctx.patchState({
|
ctx.patchState({
|
||||||
selectedPentest: stateSelectedPentest
|
selectedPentest: stateSelectedPentest
|
||||||
});
|
});
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
<ng-container [ngSwitch]="currentStatus">
|
<ng-container [ngSwitch]="currentStatus">
|
||||||
<nb-tag-list>
|
<nb-tag-list>
|
||||||
<nb-tag *ngSwitchCase="status.OPEN" status="info" appearance="filled"
|
<nb-tag *ngSwitchCase="status.PAUSED" status="info" appearance="filled"
|
||||||
text="{{getTranslationKey() | translate}}"></nb-tag>
|
text="{{getTranslationKey() | translate}}"></nb-tag>
|
||||||
<nb-tag *ngSwitchCase="status.IN_PROGRESS" status="warning" appearance="filled"
|
<nb-tag *ngSwitchCase="status.IN_PROGRESS" status="warning" appearance="filled"
|
||||||
text=" {{getTranslationKey() | translate}}"></nb-tag>
|
text=" {{getTranslationKey() | translate}}"></nb-tag>
|
||||||
|
|
|
@ -14,7 +14,7 @@ export class StatusTagComponent implements OnInit {
|
||||||
readonly statusTexts: Array<StatusText> = [
|
readonly statusTexts: Array<StatusText> = [
|
||||||
{value: PentestStatus.NOT_STARTED, translationText: 'pentest.statusText.not_started'},
|
{value: PentestStatus.NOT_STARTED, translationText: 'pentest.statusText.not_started'},
|
||||||
{value: PentestStatus.DISABLED, translationText: 'pentest.statusText.disabled'},
|
{value: PentestStatus.DISABLED, translationText: 'pentest.statusText.disabled'},
|
||||||
{value: PentestStatus.OPEN, translationText: 'pentest.statusText.open'},
|
{value: PentestStatus.PAUSED, translationText: 'pentest.statusText.paused'},
|
||||||
{value: PentestStatus.IN_PROGRESS, translationText: 'pentest.statusText.in_progress'},
|
{value: PentestStatus.IN_PROGRESS, translationText: 'pentest.statusText.in_progress'},
|
||||||
{value: PentestStatus.COMPLETED, translationText: 'pentest.statusText.completed'}
|
{value: PentestStatus.COMPLETED, translationText: 'pentest.statusText.completed'}
|
||||||
];
|
];
|
||||||
|
|
|
@ -550,7 +550,7 @@
|
||||||
"header": [],
|
"header": [],
|
||||||
"body": {
|
"body": {
|
||||||
"mode": "raw",
|
"mode": "raw",
|
||||||
"raw": "{\n \"title\": \"Test Comment\",\n \"description\": \"Test Comment Description\",\n \"relatedFindings\": []\n}",
|
"raw": "{\n \"title\": \"Test Comment\",\n \"description\": \"Test Comment Description\"\n}",
|
||||||
"options": {
|
"options": {
|
||||||
"raw": {
|
"raw": {
|
||||||
"language": "json"
|
"language": "json"
|
||||||
|
@ -700,7 +700,7 @@
|
||||||
"header": [],
|
"header": [],
|
||||||
"body": {
|
"body": {
|
||||||
"mode": "raw",
|
"mode": "raw",
|
||||||
"raw": "{\n \"title\": \"Test Comment\",\n \"description\": \"Edited Test Comment Description\",\n \"relatedFindings\": []\n}",
|
"raw": "{\n \"title\": \"Test Comment\",\n \"description\": \"Edited Test Comment Description\"\n}",
|
||||||
"options": {
|
"options": {
|
||||||
"raw": {
|
"raw": {
|
||||||
"language": "json"
|
"language": "json"
|
||||||
|
|
|
@ -14,7 +14,8 @@ data class Pentest(
|
||||||
val refNumber: String,
|
val refNumber: String,
|
||||||
val status: PentestStatus,
|
val status: PentestStatus,
|
||||||
var findingIds: List<String> = emptyList(),
|
var findingIds: List<String> = emptyList(),
|
||||||
var commentIds: List<String> = emptyList()
|
var commentIds: List<String> = emptyList(),
|
||||||
|
var timeSpent: Int
|
||||||
)
|
)
|
||||||
|
|
||||||
fun buildPentest(body: PentestRequestBody, pentestEntity: PentestEntity): Pentest {
|
fun buildPentest(body: PentestRequestBody, pentestEntity: PentestEntity): Pentest {
|
||||||
|
@ -25,7 +26,8 @@ fun buildPentest(body: PentestRequestBody, pentestEntity: PentestEntity): Pentes
|
||||||
refNumber = body.refNumber,
|
refNumber = body.refNumber,
|
||||||
status = PentestStatus.valueOf(body.status),
|
status = PentestStatus.valueOf(body.status),
|
||||||
findingIds = body.findingIds,
|
findingIds = body.findingIds,
|
||||||
commentIds = body.commentIds
|
commentIds = body.commentIds,
|
||||||
|
timeSpent = body.timeSpent
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -49,7 +51,8 @@ fun Pentest.toPentestResponseBody(): ResponseBody {
|
||||||
"refNumber" to refNumber,
|
"refNumber" to refNumber,
|
||||||
"status" to status,
|
"status" to status,
|
||||||
"findingIds" to findingIds,
|
"findingIds" to findingIds,
|
||||||
"commentIds" to commentIds
|
"commentIds" to commentIds,
|
||||||
|
"timeSpent" to timeSpent
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -81,7 +84,8 @@ data class PentestRequestBody(
|
||||||
val category: String,
|
val category: String,
|
||||||
val status: String,
|
val status: String,
|
||||||
val findingIds: List<String>,
|
val findingIds: List<String>,
|
||||||
val commentIds: List<String>
|
val commentIds: List<String>,
|
||||||
|
val timeSpent: Int
|
||||||
)
|
)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -107,6 +111,7 @@ fun PentestRequestBody.toPentest(): Pentest {
|
||||||
refNumber = this.refNumber,
|
refNumber = this.refNumber,
|
||||||
status = PentestStatus.valueOf(this.status),
|
status = PentestStatus.valueOf(this.status),
|
||||||
findingIds = this.findingIds,
|
findingIds = this.findingIds,
|
||||||
commentIds = this.commentIds
|
commentIds = this.commentIds,
|
||||||
|
timeSpent = this.timeSpent
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
@ -21,7 +21,8 @@ fun PentestEntity.toPentest(): Pentest {
|
||||||
this.data.refNumber,
|
this.data.refNumber,
|
||||||
this.data.status,
|
this.data.status,
|
||||||
this.data.findingIds,
|
this.data.findingIds,
|
||||||
this.data.commentIds
|
this.data.commentIds,
|
||||||
|
this.data.timeSpent
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -3,7 +3,7 @@ package com.securityc4po.api.pentest
|
||||||
enum class PentestStatus {
|
enum class PentestStatus {
|
||||||
NOT_STARTED,
|
NOT_STARTED,
|
||||||
DISABLED,
|
DISABLED,
|
||||||
OPEN,
|
PAUSED,
|
||||||
IN_PROGRESS,
|
IN_PROGRESS,
|
||||||
COMPLETED
|
COMPLETED
|
||||||
}
|
}
|
|
@ -10,30 +10,28 @@ data class Comment (
|
||||||
val id: String = UUID.randomUUID().toString(),
|
val id: String = UUID.randomUUID().toString(),
|
||||||
val title: String,
|
val title: String,
|
||||||
val description: String,
|
val description: String,
|
||||||
val relatedFindings: List<String>? = emptyList()
|
// List of attachment id's for file upload
|
||||||
|
val attachments: List<String>? = emptyList()
|
||||||
)
|
)
|
||||||
|
|
||||||
fun buildComment(body: CommentRequestBody, commentEntity: CommentEntity): Comment {
|
fun buildComment(body: CommentRequestBody, commentEntity: CommentEntity): Comment {
|
||||||
return Comment(
|
return Comment(
|
||||||
id = commentEntity.data.id,
|
id = commentEntity.data.id,
|
||||||
title = body.title,
|
title = body.title,
|
||||||
description = body.description,
|
description = body.description
|
||||||
relatedFindings = body.relatedFindings
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
data class CommentRequestBody(
|
data class CommentRequestBody(
|
||||||
val title: String,
|
val title: String,
|
||||||
val description: String,
|
val description: String
|
||||||
val relatedFindings: List<String>? = emptyList()
|
|
||||||
)
|
)
|
||||||
|
|
||||||
fun Comment.toCommentResponseBody(): ResponseBody {
|
fun Comment.toCommentResponseBody(): ResponseBody {
|
||||||
return mapOf(
|
return mapOf(
|
||||||
"id" to id,
|
"id" to id,
|
||||||
"title" to title,
|
"title" to title,
|
||||||
"description" to description,
|
"description" to description
|
||||||
"relatedFindings" to relatedFindings
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -60,7 +58,6 @@ fun CommentRequestBody.toComment(): Comment {
|
||||||
return Comment(
|
return Comment(
|
||||||
id = UUID.randomUUID().toString(),
|
id = UUID.randomUUID().toString(),
|
||||||
title = this.title,
|
title = this.title,
|
||||||
description = this.description,
|
description = this.description
|
||||||
relatedFindings = this.relatedFindings
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,6 +13,6 @@ fun CommentEntity.toComment(): Comment {
|
||||||
this.data.id,
|
this.data.id,
|
||||||
this.data.title,
|
this.data.title,
|
||||||
this.data.description,
|
this.data.description,
|
||||||
this.data.relatedFindings
|
this.data.attachments
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,7 +13,9 @@ data class Finding (
|
||||||
val impact: String,
|
val impact: String,
|
||||||
val affectedUrls: List<String>? = emptyList(),
|
val affectedUrls: List<String>? = emptyList(),
|
||||||
val reproduction: String,
|
val reproduction: String,
|
||||||
val mitigation: String?
|
val mitigation: String?,
|
||||||
|
// List of attachment id's for file upload
|
||||||
|
val attachments: List<String>? = emptyList()
|
||||||
)
|
)
|
||||||
|
|
||||||
fun buildFinding(body: FindingRequestBody, findingEntity: FindingEntity): Finding {
|
fun buildFinding(body: FindingRequestBody, findingEntity: FindingEntity): Finding {
|
||||||
|
|
|
@ -17,6 +17,7 @@ fun FindingEntity.toFinding(): Finding {
|
||||||
this.data.impact,
|
this.data.impact,
|
||||||
this.data.affectedUrls,
|
this.data.affectedUrls,
|
||||||
this.data.reproduction,
|
this.data.reproduction,
|
||||||
this.data.mitigation
|
this.data.mitigation,
|
||||||
|
this.data.attachments
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
@ -70,8 +70,10 @@ class PentestControllerDocumentationTest : BaseDocumentationIntTest() {
|
||||||
Preprocessors.prettyPrint()
|
Preprocessors.prettyPrint()
|
||||||
),
|
),
|
||||||
RequestDocumentation.relaxedRequestParameters(
|
RequestDocumentation.relaxedRequestParameters(
|
||||||
RequestDocumentation.parameterWithName("projectId").description("The id of the project you want to get the pentests for"),
|
RequestDocumentation.parameterWithName("projectId")
|
||||||
RequestDocumentation.parameterWithName("category").description("The category you want to get the pentests for")
|
.description("The id of the project you want to get the pentests for"),
|
||||||
|
RequestDocumentation.parameterWithName("category")
|
||||||
|
.description("The category you want to get the pentests for")
|
||||||
),
|
),
|
||||||
PayloadDocumentation.relaxedResponseFields(
|
PayloadDocumentation.relaxedResponseFields(
|
||||||
PayloadDocumentation.fieldWithPath("[].id").type(JsonFieldType.STRING)
|
PayloadDocumentation.fieldWithPath("[].id").type(JsonFieldType.STRING)
|
||||||
|
@ -87,7 +89,9 @@ class PentestControllerDocumentationTest : BaseDocumentationIntTest() {
|
||||||
PayloadDocumentation.fieldWithPath("[].findingIds").type(JsonFieldType.ARRAY)
|
PayloadDocumentation.fieldWithPath("[].findingIds").type(JsonFieldType.ARRAY)
|
||||||
.description("List of ids of the findings in the requested pentest"),
|
.description("List of ids of the findings in the requested pentest"),
|
||||||
PayloadDocumentation.fieldWithPath("[].commentIds").type(JsonFieldType.ARRAY)
|
PayloadDocumentation.fieldWithPath("[].commentIds").type(JsonFieldType.ARRAY)
|
||||||
.description("List of ids of the comments of the requested pentest")
|
.description("List of ids of the comments of the requested pentest"),
|
||||||
|
PayloadDocumentation.fieldWithPath("[].timeSpent").type(JsonFieldType.NUMBER)
|
||||||
|
.description("Time spent on the pentest")
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
@ -100,7 +104,8 @@ class PentestControllerDocumentationTest : BaseDocumentationIntTest() {
|
||||||
refNumber = "OTG-INFO-001",
|
refNumber = "OTG-INFO-001",
|
||||||
status = PentestStatus.NOT_STARTED,
|
status = PentestStatus.NOT_STARTED,
|
||||||
findingIds = emptyList(),
|
findingIds = emptyList(),
|
||||||
commentIds = emptyList()
|
commentIds = emptyList(),
|
||||||
|
timeSpent = 0
|
||||||
)
|
)
|
||||||
private val pentestTwo = Pentest(
|
private val pentestTwo = Pentest(
|
||||||
id = "43fbc63c-f624-11ec-b939-0242ac120002",
|
id = "43fbc63c-f624-11ec-b939-0242ac120002",
|
||||||
|
@ -109,7 +114,8 @@ class PentestControllerDocumentationTest : BaseDocumentationIntTest() {
|
||||||
refNumber = "OTG-INFO-002",
|
refNumber = "OTG-INFO-002",
|
||||||
status = PentestStatus.IN_PROGRESS,
|
status = PentestStatus.IN_PROGRESS,
|
||||||
findingIds = emptyList(),
|
findingIds = emptyList(),
|
||||||
commentIds = emptyList()
|
commentIds = emptyList(),
|
||||||
|
timeSpent = 0
|
||||||
)
|
)
|
||||||
|
|
||||||
private fun getProjectsResponse() = listOf(
|
private fun getProjectsResponse() = listOf(
|
||||||
|
@ -143,7 +149,8 @@ class PentestControllerDocumentationTest : BaseDocumentationIntTest() {
|
||||||
Preprocessors.prettyPrint()
|
Preprocessors.prettyPrint()
|
||||||
),
|
),
|
||||||
RequestDocumentation.relaxedPathParameters(
|
RequestDocumentation.relaxedPathParameters(
|
||||||
RequestDocumentation.parameterWithName("projectId").description("The id of the project you want to save the pentest for")
|
RequestDocumentation.parameterWithName("projectId")
|
||||||
|
.description("The id of the project you want to save the pentest for")
|
||||||
),
|
),
|
||||||
PayloadDocumentation.relaxedResponseFields(
|
PayloadDocumentation.relaxedResponseFields(
|
||||||
PayloadDocumentation.fieldWithPath("id").type(JsonFieldType.STRING)
|
PayloadDocumentation.fieldWithPath("id").type(JsonFieldType.STRING)
|
||||||
|
@ -159,7 +166,9 @@ class PentestControllerDocumentationTest : BaseDocumentationIntTest() {
|
||||||
PayloadDocumentation.fieldWithPath("findingIds").type(JsonFieldType.ARRAY)
|
PayloadDocumentation.fieldWithPath("findingIds").type(JsonFieldType.ARRAY)
|
||||||
.description("List of ids of the findings in the created pentest"),
|
.description("List of ids of the findings in the created pentest"),
|
||||||
PayloadDocumentation.fieldWithPath("commentIds").type(JsonFieldType.ARRAY)
|
PayloadDocumentation.fieldWithPath("commentIds").type(JsonFieldType.ARRAY)
|
||||||
.description("List of ids of the comments of the created pentest")
|
.description("List of ids of the comments of the created pentest"),
|
||||||
|
PayloadDocumentation.fieldWithPath("timeSpent").type(JsonFieldType.NUMBER)
|
||||||
|
.description("Time spent on the pentest")
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
@ -171,7 +180,8 @@ class PentestControllerDocumentationTest : BaseDocumentationIntTest() {
|
||||||
refNumber = "OTG-CLIENT-001",
|
refNumber = "OTG-CLIENT-001",
|
||||||
status = "IN_PROGRESS",
|
status = "IN_PROGRESS",
|
||||||
findingIds = emptyList<String>(),
|
findingIds = emptyList<String>(),
|
||||||
commentIds = emptyList<String>()
|
commentIds = emptyList<String>(),
|
||||||
|
timeSpent = 0
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -200,7 +210,8 @@ class PentestControllerDocumentationTest : BaseDocumentationIntTest() {
|
||||||
Preprocessors.prettyPrint()
|
Preprocessors.prettyPrint()
|
||||||
),
|
),
|
||||||
RequestDocumentation.relaxedPathParameters(
|
RequestDocumentation.relaxedPathParameters(
|
||||||
RequestDocumentation.parameterWithName("pentestId").description("The id of the pentest you want to update")
|
RequestDocumentation.parameterWithName("pentestId")
|
||||||
|
.description("The id of the pentest you want to update")
|
||||||
),
|
),
|
||||||
PayloadDocumentation.relaxedResponseFields(
|
PayloadDocumentation.relaxedResponseFields(
|
||||||
PayloadDocumentation.fieldWithPath("id").type(JsonFieldType.STRING)
|
PayloadDocumentation.fieldWithPath("id").type(JsonFieldType.STRING)
|
||||||
|
@ -216,7 +227,9 @@ class PentestControllerDocumentationTest : BaseDocumentationIntTest() {
|
||||||
PayloadDocumentation.fieldWithPath("findingIds").type(JsonFieldType.ARRAY)
|
PayloadDocumentation.fieldWithPath("findingIds").type(JsonFieldType.ARRAY)
|
||||||
.description("List of ids of the findings in the updated pentest"),
|
.description("List of ids of the findings in the updated pentest"),
|
||||||
PayloadDocumentation.fieldWithPath("commentIds").type(JsonFieldType.ARRAY)
|
PayloadDocumentation.fieldWithPath("commentIds").type(JsonFieldType.ARRAY)
|
||||||
.description("List of ids of the comments of the updated pentest")
|
.description("List of ids of the comments of the updated pentest"),
|
||||||
|
PayloadDocumentation.fieldWithPath("timeSpent").type(JsonFieldType.NUMBER)
|
||||||
|
.description("Time spent on the pentest")
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
@ -226,9 +239,10 @@ class PentestControllerDocumentationTest : BaseDocumentationIntTest() {
|
||||||
projectId = "d2e126ba-f608-11ec-b939-0242ac120025",
|
projectId = "d2e126ba-f608-11ec-b939-0242ac120025",
|
||||||
category = "INFORMATION_GATHERING",
|
category = "INFORMATION_GATHERING",
|
||||||
refNumber = "OTG-INFO-001",
|
refNumber = "OTG-INFO-001",
|
||||||
status = "OPEN",
|
status = "PAUSED",
|
||||||
findingIds = emptyList<String>(),
|
findingIds = emptyList<String>(),
|
||||||
commentIds = emptyList<String>()
|
commentIds = emptyList<String>(),
|
||||||
|
timeSpent = 0
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -252,7 +266,8 @@ class PentestControllerDocumentationTest : BaseDocumentationIntTest() {
|
||||||
refNumber = "OTG-INFO-001",
|
refNumber = "OTG-INFO-001",
|
||||||
status = PentestStatus.NOT_STARTED,
|
status = PentestStatus.NOT_STARTED,
|
||||||
findingIds = emptyList(),
|
findingIds = emptyList(),
|
||||||
commentIds = emptyList()
|
commentIds = emptyList(),
|
||||||
|
timeSpent = 0
|
||||||
)
|
)
|
||||||
val pentestTwo = Pentest(
|
val pentestTwo = Pentest(
|
||||||
id = "43fbc63c-f624-11ec-b939-0242ac120002",
|
id = "43fbc63c-f624-11ec-b939-0242ac120002",
|
||||||
|
@ -261,7 +276,8 @@ class PentestControllerDocumentationTest : BaseDocumentationIntTest() {
|
||||||
refNumber = "OTG-INFO-002",
|
refNumber = "OTG-INFO-002",
|
||||||
status = PentestStatus.IN_PROGRESS,
|
status = PentestStatus.IN_PROGRESS,
|
||||||
findingIds = emptyList(),
|
findingIds = emptyList(),
|
||||||
commentIds = emptyList()
|
commentIds = emptyList(),
|
||||||
|
timeSpent = 0
|
||||||
)
|
)
|
||||||
val pentestThree = Pentest(
|
val pentestThree = Pentest(
|
||||||
id = "74eae112-f62c-11ec-b939-0242ac120002",
|
id = "74eae112-f62c-11ec-b939-0242ac120002",
|
||||||
|
@ -270,7 +286,8 @@ class PentestControllerDocumentationTest : BaseDocumentationIntTest() {
|
||||||
refNumber = "OTG-AUTHN-001",
|
refNumber = "OTG-AUTHN-001",
|
||||||
status = PentestStatus.COMPLETED,
|
status = PentestStatus.COMPLETED,
|
||||||
findingIds = emptyList(),
|
findingIds = emptyList(),
|
||||||
commentIds = emptyList()
|
commentIds = emptyList(),
|
||||||
|
timeSpent = 0
|
||||||
)
|
)
|
||||||
// persist test data in database
|
// persist test data in database
|
||||||
mongoTemplate.save(ProjectEntity(projectOne))
|
mongoTemplate.save(ProjectEntity(projectOne))
|
||||||
|
|
|
@ -77,7 +77,8 @@ class PentestControllerIntTest : BaseIntTest() {
|
||||||
refNumber = "OTG-INFO-001",
|
refNumber = "OTG-INFO-001",
|
||||||
status = PentestStatus.NOT_STARTED,
|
status = PentestStatus.NOT_STARTED,
|
||||||
findingIds = emptyList(),
|
findingIds = emptyList(),
|
||||||
commentIds = emptyList()
|
commentIds = emptyList(),
|
||||||
|
timeSpent = 0
|
||||||
)
|
)
|
||||||
private val pentestTwo = Pentest(
|
private val pentestTwo = Pentest(
|
||||||
id = "43fbc63c-f624-11ec-b939-0242ac120002",
|
id = "43fbc63c-f624-11ec-b939-0242ac120002",
|
||||||
|
@ -86,7 +87,8 @@ class PentestControllerIntTest : BaseIntTest() {
|
||||||
refNumber = "OTG-INFO-002",
|
refNumber = "OTG-INFO-002",
|
||||||
status = PentestStatus.IN_PROGRESS,
|
status = PentestStatus.IN_PROGRESS,
|
||||||
findingIds = emptyList(),
|
findingIds = emptyList(),
|
||||||
commentIds = emptyList()
|
commentIds = emptyList(),
|
||||||
|
timeSpent = 0
|
||||||
)
|
)
|
||||||
|
|
||||||
private fun getPentests() = listOf(
|
private fun getPentests() = listOf(
|
||||||
|
@ -122,7 +124,8 @@ class PentestControllerIntTest : BaseIntTest() {
|
||||||
refNumber = "OTG-CLIENT-001",
|
refNumber = "OTG-CLIENT-001",
|
||||||
status = "IN_PROGRESS",
|
status = "IN_PROGRESS",
|
||||||
findingIds = emptyList<String>(),
|
findingIds = emptyList<String>(),
|
||||||
commentIds = emptyList<String>()
|
commentIds = emptyList<String>(),
|
||||||
|
timeSpent = 0
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -143,7 +146,7 @@ class PentestControllerIntTest : BaseIntTest() {
|
||||||
.jsonPath("$.projectId").isEqualTo("d2e126ba-f608-11ec-b939-0242ac120025")
|
.jsonPath("$.projectId").isEqualTo("d2e126ba-f608-11ec-b939-0242ac120025")
|
||||||
.jsonPath("$.category").isEqualTo("INFORMATION_GATHERING")
|
.jsonPath("$.category").isEqualTo("INFORMATION_GATHERING")
|
||||||
.jsonPath("$.refNumber").isEqualTo("OTG-INFO-001")
|
.jsonPath("$.refNumber").isEqualTo("OTG-INFO-001")
|
||||||
.jsonPath("$.status").isEqualTo("OPEN")
|
.jsonPath("$.status").isEqualTo("PAUSED")
|
||||||
.jsonPath("$.findingIds").isEmpty
|
.jsonPath("$.findingIds").isEmpty
|
||||||
.jsonPath("$.commentIds").isEmpty
|
.jsonPath("$.commentIds").isEmpty
|
||||||
}
|
}
|
||||||
|
@ -152,9 +155,10 @@ class PentestControllerIntTest : BaseIntTest() {
|
||||||
projectId = "d2e126ba-f608-11ec-b939-0242ac120025",
|
projectId = "d2e126ba-f608-11ec-b939-0242ac120025",
|
||||||
category = "INFORMATION_GATHERING",
|
category = "INFORMATION_GATHERING",
|
||||||
refNumber = "OTG-INFO-001",
|
refNumber = "OTG-INFO-001",
|
||||||
status = "OPEN",
|
status = "PAUSED",
|
||||||
findingIds = emptyList<String>(),
|
findingIds = emptyList<String>(),
|
||||||
commentIds = emptyList<String>()
|
commentIds = emptyList<String>(),
|
||||||
|
timeSpent = 24
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -177,7 +181,8 @@ class PentestControllerIntTest : BaseIntTest() {
|
||||||
refNumber = "OTG-INFO-001",
|
refNumber = "OTG-INFO-001",
|
||||||
status = PentestStatus.NOT_STARTED,
|
status = PentestStatus.NOT_STARTED,
|
||||||
findingIds = emptyList(),
|
findingIds = emptyList(),
|
||||||
commentIds = emptyList()
|
commentIds = emptyList(),
|
||||||
|
timeSpent = 0
|
||||||
)
|
)
|
||||||
val pentestTwo = Pentest(
|
val pentestTwo = Pentest(
|
||||||
id = "43fbc63c-f624-11ec-b939-0242ac120002",
|
id = "43fbc63c-f624-11ec-b939-0242ac120002",
|
||||||
|
@ -186,7 +191,8 @@ class PentestControllerIntTest : BaseIntTest() {
|
||||||
refNumber = "OTG-INFO-002",
|
refNumber = "OTG-INFO-002",
|
||||||
status = PentestStatus.IN_PROGRESS,
|
status = PentestStatus.IN_PROGRESS,
|
||||||
findingIds = emptyList(),
|
findingIds = emptyList(),
|
||||||
commentIds = emptyList()
|
commentIds = emptyList(),
|
||||||
|
timeSpent = 0
|
||||||
)
|
)
|
||||||
val pentestThree = Pentest(
|
val pentestThree = Pentest(
|
||||||
id = "16vbc63c-f624-11ec-b939-0242ac120002",
|
id = "16vbc63c-f624-11ec-b939-0242ac120002",
|
||||||
|
@ -195,7 +201,8 @@ class PentestControllerIntTest : BaseIntTest() {
|
||||||
refNumber = "OTG-AUTHN-001",
|
refNumber = "OTG-AUTHN-001",
|
||||||
status = PentestStatus.COMPLETED,
|
status = PentestStatus.COMPLETED,
|
||||||
findingIds = emptyList(),
|
findingIds = emptyList(),
|
||||||
commentIds = emptyList()
|
commentIds = emptyList(),
|
||||||
|
timeSpent = 0
|
||||||
)
|
)
|
||||||
// persist test data in database
|
// persist test data in database
|
||||||
mongoTemplate.save(ProjectEntity(projectOne))
|
mongoTemplate.save(ProjectEntity(projectOne))
|
||||||
|
|
|
@ -302,7 +302,8 @@ class CommentControllerDocumentationTest : BaseDocumentationIntTest() {
|
||||||
refNumber = "OTG-INFO-001",
|
refNumber = "OTG-INFO-001",
|
||||||
status = PentestStatus.NOT_STARTED,
|
status = PentestStatus.NOT_STARTED,
|
||||||
findingIds = emptyList(),
|
findingIds = emptyList(),
|
||||||
commentIds = emptyList()
|
commentIds = emptyList(),
|
||||||
|
timeSpent = 0
|
||||||
)
|
)
|
||||||
val pentestTwo = Pentest(
|
val pentestTwo = Pentest(
|
||||||
id = "43fbc63c-f624-11ec-b939-0242ac120002",
|
id = "43fbc63c-f624-11ec-b939-0242ac120002",
|
||||||
|
@ -311,7 +312,8 @@ class CommentControllerDocumentationTest : BaseDocumentationIntTest() {
|
||||||
refNumber = "OTG-INFO-002",
|
refNumber = "OTG-INFO-002",
|
||||||
status = PentestStatus.IN_PROGRESS,
|
status = PentestStatus.IN_PROGRESS,
|
||||||
findingIds = emptyList(),
|
findingIds = emptyList(),
|
||||||
commentIds = listOf("ab62d365-1b1d-4da1-89bc-5496616e220f")
|
commentIds = listOf("ab62d365-1b1d-4da1-89bc-5496616e220f"),
|
||||||
|
timeSpent = 56
|
||||||
)
|
)
|
||||||
val pentestThree = Pentest(
|
val pentestThree = Pentest(
|
||||||
id = "74eae112-f62c-11ec-b939-0242ac120002",
|
id = "74eae112-f62c-11ec-b939-0242ac120002",
|
||||||
|
@ -320,7 +322,8 @@ class CommentControllerDocumentationTest : BaseDocumentationIntTest() {
|
||||||
refNumber = "OTG-AUTHN-001",
|
refNumber = "OTG-AUTHN-001",
|
||||||
status = PentestStatus.COMPLETED,
|
status = PentestStatus.COMPLETED,
|
||||||
findingIds = emptyList(),
|
findingIds = emptyList(),
|
||||||
commentIds = emptyList()
|
commentIds = emptyList(),
|
||||||
|
timeSpent = 124
|
||||||
)
|
)
|
||||||
// Comment
|
// Comment
|
||||||
val commentOne = Comment(
|
val commentOne = Comment(
|
||||||
|
|
|
@ -193,7 +193,8 @@ class CommentControllerIntTest : BaseIntTest() {
|
||||||
refNumber = "OTG-INFO-001",
|
refNumber = "OTG-INFO-001",
|
||||||
status = PentestStatus.NOT_STARTED,
|
status = PentestStatus.NOT_STARTED,
|
||||||
findingIds = emptyList(),
|
findingIds = emptyList(),
|
||||||
commentIds = emptyList()
|
commentIds = emptyList(),
|
||||||
|
timeSpent = 0
|
||||||
)
|
)
|
||||||
val pentestTwo = Pentest(
|
val pentestTwo = Pentest(
|
||||||
id = "43fbc63c-f624-11ec-b939-0242ac120002",
|
id = "43fbc63c-f624-11ec-b939-0242ac120002",
|
||||||
|
@ -202,7 +203,8 @@ class CommentControllerIntTest : BaseIntTest() {
|
||||||
refNumber = "OTG-INFO-002",
|
refNumber = "OTG-INFO-002",
|
||||||
status = PentestStatus.IN_PROGRESS,
|
status = PentestStatus.IN_PROGRESS,
|
||||||
findingIds = emptyList(),
|
findingIds = emptyList(),
|
||||||
commentIds = listOf("ab62d365-1b1d-4da1-89bc-5496616e220f")
|
commentIds = listOf("ab62d365-1b1d-4da1-89bc-5496616e220f"),
|
||||||
|
timeSpent = 56
|
||||||
)
|
)
|
||||||
val pentestThree = Pentest(
|
val pentestThree = Pentest(
|
||||||
id = "16vbc63c-f624-11ec-b939-0242ac120002",
|
id = "16vbc63c-f624-11ec-b939-0242ac120002",
|
||||||
|
@ -211,7 +213,8 @@ class CommentControllerIntTest : BaseIntTest() {
|
||||||
refNumber = "OTG-AUTHN-001",
|
refNumber = "OTG-AUTHN-001",
|
||||||
status = PentestStatus.COMPLETED,
|
status = PentestStatus.COMPLETED,
|
||||||
findingIds = emptyList(),
|
findingIds = emptyList(),
|
||||||
commentIds = emptyList()
|
commentIds = emptyList(),
|
||||||
|
timeSpent = 124
|
||||||
)
|
)
|
||||||
// Comment
|
// Comment
|
||||||
val commentOne = Comment(
|
val commentOne = Comment(
|
||||||
|
|
|
@ -350,7 +350,8 @@ class FindingControllerDocumentationTest: BaseDocumentationIntTest() {
|
||||||
refNumber = "OTG-INFO-001",
|
refNumber = "OTG-INFO-001",
|
||||||
status = PentestStatus.NOT_STARTED,
|
status = PentestStatus.NOT_STARTED,
|
||||||
findingIds = emptyList(),
|
findingIds = emptyList(),
|
||||||
commentIds = emptyList()
|
commentIds = emptyList(),
|
||||||
|
timeSpent = 0
|
||||||
)
|
)
|
||||||
val pentestTwo = Pentest(
|
val pentestTwo = Pentest(
|
||||||
id = "43fbc63c-f624-11ec-b939-0242ac120002",
|
id = "43fbc63c-f624-11ec-b939-0242ac120002",
|
||||||
|
@ -359,7 +360,8 @@ class FindingControllerDocumentationTest: BaseDocumentationIntTest() {
|
||||||
refNumber = "OTG-INFO-002",
|
refNumber = "OTG-INFO-002",
|
||||||
status = PentestStatus.IN_PROGRESS,
|
status = PentestStatus.IN_PROGRESS,
|
||||||
findingIds = listOf("ab62d365-1b1d-4da1-89bc-5496616e220f"),
|
findingIds = listOf("ab62d365-1b1d-4da1-89bc-5496616e220f"),
|
||||||
commentIds = emptyList()
|
commentIds = emptyList(),
|
||||||
|
timeSpent = 56
|
||||||
)
|
)
|
||||||
val pentestThree = Pentest(
|
val pentestThree = Pentest(
|
||||||
id = "74eae112-f62c-11ec-b939-0242ac120002",
|
id = "74eae112-f62c-11ec-b939-0242ac120002",
|
||||||
|
@ -368,7 +370,8 @@ class FindingControllerDocumentationTest: BaseDocumentationIntTest() {
|
||||||
refNumber = "OTG-AUTHN-001",
|
refNumber = "OTG-AUTHN-001",
|
||||||
status = PentestStatus.COMPLETED,
|
status = PentestStatus.COMPLETED,
|
||||||
findingIds = emptyList(),
|
findingIds = emptyList(),
|
||||||
commentIds = emptyList()
|
commentIds = emptyList(),
|
||||||
|
timeSpent = 124
|
||||||
)
|
)
|
||||||
// Finding
|
// Finding
|
||||||
val findingOne = Finding(
|
val findingOne = Finding(
|
||||||
|
|
|
@ -217,7 +217,8 @@ class FindingControllerIntTest: BaseIntTest() {
|
||||||
refNumber = "OTG-INFO-001",
|
refNumber = "OTG-INFO-001",
|
||||||
status = PentestStatus.NOT_STARTED,
|
status = PentestStatus.NOT_STARTED,
|
||||||
findingIds = emptyList(),
|
findingIds = emptyList(),
|
||||||
commentIds = emptyList()
|
commentIds = emptyList(),
|
||||||
|
timeSpent = 0
|
||||||
)
|
)
|
||||||
val pentestTwo = Pentest(
|
val pentestTwo = Pentest(
|
||||||
id = "43fbc63c-f624-11ec-b939-0242ac120002",
|
id = "43fbc63c-f624-11ec-b939-0242ac120002",
|
||||||
|
@ -226,7 +227,8 @@ class FindingControllerIntTest: BaseIntTest() {
|
||||||
refNumber = "OTG-INFO-002",
|
refNumber = "OTG-INFO-002",
|
||||||
status = PentestStatus.IN_PROGRESS,
|
status = PentestStatus.IN_PROGRESS,
|
||||||
findingIds = listOf("ab62d365-1b1d-4da1-89bc-5496616e220f"),
|
findingIds = listOf("ab62d365-1b1d-4da1-89bc-5496616e220f"),
|
||||||
commentIds = emptyList()
|
commentIds = emptyList(),
|
||||||
|
timeSpent = 56
|
||||||
)
|
)
|
||||||
val pentestThree = Pentest(
|
val pentestThree = Pentest(
|
||||||
id = "16vbc63c-f624-11ec-b939-0242ac120002",
|
id = "16vbc63c-f624-11ec-b939-0242ac120002",
|
||||||
|
@ -235,7 +237,8 @@ class FindingControllerIntTest: BaseIntTest() {
|
||||||
refNumber = "OTG-AUTHN-001",
|
refNumber = "OTG-AUTHN-001",
|
||||||
status = PentestStatus.COMPLETED,
|
status = PentestStatus.COMPLETED,
|
||||||
findingIds = emptyList(),
|
findingIds = emptyList(),
|
||||||
commentIds = emptyList()
|
commentIds = emptyList(),
|
||||||
|
timeSpent = 124
|
||||||
)
|
)
|
||||||
// Finding
|
// Finding
|
||||||
val findingOne = Finding(
|
val findingOne = Finding(
|
||||||
|
|
|
@ -1,54 +1,33 @@
|
||||||
[{
|
[{
|
||||||
"_id": {
|
"_id": {
|
||||||
"$oid": "63a4530b9bb2aa2c3bc77b52"
|
"$oid": "6405dbf113ae975803a09901"
|
||||||
},
|
},
|
||||||
"lastModified": {
|
"lastModified": {
|
||||||
"$date": {
|
"$date": {
|
||||||
"$numberLong": "1671713547508"
|
"$numberLong": "1678105585081"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"data": {
|
"data": {
|
||||||
"_id": "89703b19-16c7-49e5-8e33-0c706313e5fe",
|
"_id": "85935303-e5b7-48ca-a504-910c1a94fb1f",
|
||||||
"title": "Test Comment",
|
"title": "Uninteresting comment",
|
||||||
"description": "No related findings",
|
"description": "Nothing",
|
||||||
"relatedFindings": []
|
"attachments": []
|
||||||
},
|
},
|
||||||
"_class": "com.securityc4po.api.comment.CommentEntity"
|
"_class": "com.securityc4po.api.pentest.comment.CommentEntity"
|
||||||
},{
|
},{
|
||||||
"_id": {
|
"_id": {
|
||||||
"$oid": "63a453e4377c3f53f86d27d8"
|
"$oid": "6405dc0513ae975803a09902"
|
||||||
},
|
},
|
||||||
"lastModified": {
|
"lastModified": {
|
||||||
"$date": {
|
"$date": {
|
||||||
"$numberLong": "1671713764781"
|
"$numberLong": "1678105605811"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"data": {
|
"data": {
|
||||||
"_id": "df516de6-ca5e-44a6-ac50-db89bb17aac3",
|
"_id": "a785aaf0-1feb-429e-beb1-31bfcf70c404",
|
||||||
"title": "New Test Comment",
|
"title": "Interesting comment",
|
||||||
"description": "Two related findings",
|
"description": "I know where your house lives",
|
||||||
"relatedFindings": [
|
"attachments": []
|
||||||
"0bda8950-94fa-4ec6-8fa7-e09f5a8cd3e8",
|
|
||||||
"4ddb84f6-068c-4319-a8ee-1000008bb75a"
|
|
||||||
]
|
|
||||||
},
|
},
|
||||||
"_class": "com.securityc4po.api.comment.CommentEntity"
|
"_class": "com.securityc4po.api.pentest.comment.CommentEntity"
|
||||||
},{
|
|
||||||
"_id": {
|
|
||||||
"$oid": "63a454b5377c3f53f86d27d9"
|
|
||||||
},
|
|
||||||
"lastModified": {
|
|
||||||
"$date": {
|
|
||||||
"$numberLong": "1671713973541"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"data": {
|
|
||||||
"_id": "e55e943b-6a48-4d84-8d72-b48d7d9de5b7",
|
|
||||||
"title": "Another Test Comment",
|
|
||||||
"description": "One related findings",
|
|
||||||
"relatedFindings": [
|
|
||||||
"5e22d38f-a4f6-4809-84ea-a803b5f1f9fc"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"_class": "com.securityc4po.api.comment.CommentEntity"
|
|
||||||
}]
|
}]
|
|
@ -1,357 +1,106 @@
|
||||||
[{
|
[{
|
||||||
"_id": {
|
"_id": {
|
||||||
"$oid": "6372223efea5724fd22bae8a"
|
"$oid": "6405d88b13ae975803a098fb"
|
||||||
},
|
},
|
||||||
"lastModified": {
|
"lastModified": {
|
||||||
"$date": {
|
"$date": {
|
||||||
"$numberLong": "1668424254533"
|
"$numberLong": "1678104715816"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"data": {
|
"data": {
|
||||||
"_id": "ef31449d-71ec-4736-952f-8b20e53117d5",
|
"_id": "a343150a-91c9-4564-9638-d0377eecc7c9",
|
||||||
"severity": "LOW",
|
"severity": "LOW",
|
||||||
"title": "Test Title",
|
"title": "Low Prio Finding",
|
||||||
"description": "Test Description",
|
"description": "This is Low Prio.",
|
||||||
"impact": "Test Impact",
|
"impact": "Impacts nothing.",
|
||||||
"affectedUrls": [
|
"affectedUrls": [],
|
||||||
"https://akveo.github.io/nebular/docs/components/progress-bar/examples#nbprogressbarcomponent"
|
"reproduction": "Open App.",
|
||||||
],
|
"mitigation": "",
|
||||||
"reproduction": "Step 1: Test",
|
"attachments": []
|
||||||
"mitigation": "Test Mitigatin"
|
|
||||||
},
|
},
|
||||||
"_class": "com.securityc4po.api.finding.FindingEntity"
|
"_class": "com.securityc4po.api.pentest.finding.FindingEntity"
|
||||||
},{
|
},{
|
||||||
"_id": {
|
"_id": {
|
||||||
"$oid": "63725fa6e612626e2c6956ee"
|
"$oid": "6405db8a13ae975803a098fe"
|
||||||
},
|
},
|
||||||
"lastModified": {
|
"lastModified": {
|
||||||
"$date": {
|
"$date": {
|
||||||
"$numberLong": "1668439974730"
|
"$numberLong": "1678105482494"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"data": {
|
"data": {
|
||||||
"_id": "0bda8950-94fa-4ec6-8fa7-e09f5a8cd3e8",
|
"_id": "5bf1b2e1-69b7-463b-a1ca-4ac6ac66b10f",
|
||||||
|
"severity": "MEDIUM",
|
||||||
|
"title": "Medium Prio Finding",
|
||||||
|
"description": "Medium Description",
|
||||||
|
"impact": "Medium Impact",
|
||||||
|
"affectedUrls": [],
|
||||||
|
"reproduction": "1. Open App",
|
||||||
|
"mitigation": "",
|
||||||
|
"attachments": []
|
||||||
|
},
|
||||||
|
"_class": "com.securityc4po.api.pentest.finding.FindingEntity"
|
||||||
|
},{
|
||||||
|
"_id": {
|
||||||
|
"$oid": "6405dba513ae975803a098ff"
|
||||||
|
},
|
||||||
|
"lastModified": {
|
||||||
|
"$date": {
|
||||||
|
"$numberLong": "1678105509645"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"data": {
|
||||||
|
"_id": "f6e6c632-ab34-479e-9584-565f61c5862a",
|
||||||
"severity": "HIGH",
|
"severity": "HIGH",
|
||||||
"title": "High Title",
|
"title": "High Prio Finding",
|
||||||
"description": "High Description",
|
"description": "High Prio Description",
|
||||||
"impact": "High Impact",
|
"impact": "High Impact",
|
||||||
"affectedUrls": [
|
|
||||||
"https://angular.io/guide/routing-overview"
|
|
||||||
],
|
|
||||||
"reproduction": "Step 1: Not be High",
|
|
||||||
"mitigation": ""
|
|
||||||
},
|
|
||||||
"_class": "com.securityc4po.api.finding.FindingEntity"
|
|
||||||
},{
|
|
||||||
"_id": {
|
|
||||||
"$oid": "6374c3c4e0136563b96187b8"
|
|
||||||
},
|
|
||||||
"lastModified": {
|
|
||||||
"$date": {
|
|
||||||
"$numberLong": "1668596676210"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"data": {
|
|
||||||
"_id": "58f63b4e-97fb-4fe8-8527-7996896089d2",
|
|
||||||
"severity": "MEDIUM",
|
|
||||||
"title": "Medium Finding",
|
|
||||||
"description": "Medium",
|
|
||||||
"impact": "Medium",
|
|
||||||
"affectedUrls": [],
|
"affectedUrls": [],
|
||||||
"reproduction": "Medium",
|
"reproduction": "1. Open App\n2. Hack",
|
||||||
"mitigation": ""
|
"mitigation": "",
|
||||||
|
"attachments": []
|
||||||
},
|
},
|
||||||
"_class": "com.securityc4po.api.finding.FindingEntity"
|
"_class": "com.securityc4po.api.pentest.finding.FindingEntity"
|
||||||
},{
|
},{
|
||||||
"_id": {
|
"_id": {
|
||||||
"$oid": "6374c43be0136563b96187b9"
|
"$oid": "6405dbcc13ae975803a09900"
|
||||||
},
|
},
|
||||||
"lastModified": {
|
"lastModified": {
|
||||||
"$date": {
|
"$date": {
|
||||||
"$numberLong": "1668596795003"
|
"$numberLong": "1678105548815"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"data": {
|
"data": {
|
||||||
"_id": "72886128-b2d9-4a92-bbfe-b54373441321",
|
"_id": "176f5d93-0fe3-40b1-8a25-f11a6f760148",
|
||||||
"severity": "CRITICAL",
|
"severity": "CRITICAL",
|
||||||
"title": "Critical Issue",
|
"title": "Critical Prio Finding",
|
||||||
"description": "Critical",
|
"description": "Critical Description",
|
||||||
"impact": "Critical",
|
"impact": "Critical Impact",
|
||||||
"affectedUrls": [],
|
"affectedUrls": [],
|
||||||
"reproduction": "Critical",
|
"reproduction": "1. Open App\n2. Hack\n3. Break everything",
|
||||||
"mitigation": ""
|
"mitigation": "",
|
||||||
|
"attachments": []
|
||||||
},
|
},
|
||||||
"_class": "com.securityc4po.api.finding.FindingEntity"
|
"_class": "com.securityc4po.api.pentest.finding.FindingEntity"
|
||||||
},{
|
},{
|
||||||
"_id": {
|
"_id": {
|
||||||
"$oid": "6374c488e0136563b96187ba"
|
"$oid": "640854a01d5b385d85c60ba7"
|
||||||
},
|
},
|
||||||
"lastModified": {
|
"lastModified": {
|
||||||
"$date": {
|
"$date": {
|
||||||
"$numberLong": "1668596872152"
|
"$numberLong": "1678267552968"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"data": {
|
"data": {
|
||||||
"_id": "4ddb84f6-068c-4319-a8ee-1000008bb75a",
|
"_id": "1ffc2215-b8ae-43b7-bbb7-bfcfb414d534",
|
||||||
"severity": "HIGH",
|
|
||||||
"title": "Anothe High Issues",
|
|
||||||
"description": "High",
|
|
||||||
"impact": "High",
|
|
||||||
"affectedUrls": [],
|
|
||||||
"reproduction": "High",
|
|
||||||
"mitigation": ""
|
|
||||||
},
|
|
||||||
"_class": "com.securityc4po.api.finding.FindingEntity"
|
|
||||||
},{
|
|
||||||
"_id": {
|
|
||||||
"$oid": "6374c624e0136563b96187bb"
|
|
||||||
},
|
|
||||||
"lastModified": {
|
|
||||||
"$date": {
|
|
||||||
"$numberLong": "1668597284983"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"data": {
|
|
||||||
"_id": "42831151-51fd-4348-b829-6b18ddd14fe1",
|
|
||||||
"severity": "MEDIUM",
|
|
||||||
"title": "Another Medium FInding",
|
|
||||||
"description": "Medium",
|
|
||||||
"impact": "Medium",
|
|
||||||
"affectedUrls": [],
|
|
||||||
"reproduction": "Medium",
|
|
||||||
"mitigation": ""
|
|
||||||
},
|
|
||||||
"_class": "com.securityc4po.api.finding.FindingEntity"
|
|
||||||
},{
|
|
||||||
"_id": {
|
|
||||||
"$oid": "6374cb33e0136563b96187bc"
|
|
||||||
},
|
|
||||||
"lastModified": {
|
|
||||||
"$date": {
|
|
||||||
"$numberLong": "1668598579443"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"data": {
|
|
||||||
"_id": "559cd0ac-9e64-41f9-892a-4c8a9dd30357",
|
|
||||||
"severity": "LOW",
|
"severity": "LOW",
|
||||||
"title": "Another Low One",
|
"title": "Low Prio Title",
|
||||||
"description": "Low",
|
"description": "Low Prio Description",
|
||||||
"impact": "Low",
|
"impact": "Low Prio Impact",
|
||||||
"affectedUrls": [],
|
"affectedUrls": [],
|
||||||
"reproduction": "Low",
|
"reproduction": "Do Nothing",
|
||||||
"mitigation": ""
|
"mitigation": "",
|
||||||
|
"attachments": []
|
||||||
},
|
},
|
||||||
"_class": "com.securityc4po.api.finding.FindingEntity"
|
"_class": "com.securityc4po.api.pentest.finding.FindingEntity"
|
||||||
},{
|
|
||||||
"_id": {
|
|
||||||
"$oid": "6374cb98e0136563b96187bd"
|
|
||||||
},
|
|
||||||
"lastModified": {
|
|
||||||
"$date": {
|
|
||||||
"$numberLong": "1668598680140"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"data": {
|
|
||||||
"_id": "5e22d38f-a4f6-4809-84ea-a803b5f1f9fc",
|
|
||||||
"severity": "LOW",
|
|
||||||
"title": "common",
|
|
||||||
"description": "common",
|
|
||||||
"impact": "common",
|
|
||||||
"affectedUrls": [],
|
|
||||||
"reproduction": "common",
|
|
||||||
"mitigation": ""
|
|
||||||
},
|
|
||||||
"_class": "com.securityc4po.api.finding.FindingEntity"
|
|
||||||
},{
|
|
||||||
"_id": {
|
|
||||||
"$oid": "6374cc51e0136563b96187be"
|
|
||||||
},
|
|
||||||
"lastModified": {
|
|
||||||
"$date": {
|
|
||||||
"$numberLong": "1668598865728"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"data": {
|
|
||||||
"_id": "0bfa7511-fe33-4ab5-9af2-d4ed70c1b350",
|
|
||||||
"severity": "HIGH",
|
|
||||||
"title": "Highihihi",
|
|
||||||
"description": "High",
|
|
||||||
"impact": "High",
|
|
||||||
"affectedUrls": [],
|
|
||||||
"reproduction": "High",
|
|
||||||
"mitigation": ""
|
|
||||||
},
|
|
||||||
"_class": "com.securityc4po.api.finding.FindingEntity"
|
|
||||||
},{
|
|
||||||
"_id": {
|
|
||||||
"$oid": "6374cd00e0136563b96187bf"
|
|
||||||
},
|
|
||||||
"lastModified": {
|
|
||||||
"$date": {
|
|
||||||
"$numberLong": "1668599040593"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"data": {
|
|
||||||
"_id": "70e413b9-d736-40d2-b7d6-236768b1230c",
|
|
||||||
"severity": "MEDIUM",
|
|
||||||
"title": "Medium Rare",
|
|
||||||
"description": "Medium",
|
|
||||||
"impact": "Medium",
|
|
||||||
"affectedUrls": [],
|
|
||||||
"reproduction": "Medium",
|
|
||||||
"mitigation": ""
|
|
||||||
},
|
|
||||||
"_class": "com.securityc4po.api.finding.FindingEntity"
|
|
||||||
},{
|
|
||||||
"_id": {
|
|
||||||
"$oid": "6374ec35e0136563b96187c8"
|
|
||||||
},
|
|
||||||
"lastModified": {
|
|
||||||
"$date": {
|
|
||||||
"$numberLong": "1668607029072"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"data": {
|
|
||||||
"_id": "672d9f87-fb3d-4fc5-8c6f-cadf97661ca5",
|
|
||||||
"severity": "HIGH",
|
|
||||||
"title": "Test",
|
|
||||||
"description": "Test",
|
|
||||||
"impact": "Test",
|
|
||||||
"affectedUrls": [],
|
|
||||||
"reproduction": "Test",
|
|
||||||
"mitigation": ""
|
|
||||||
},
|
|
||||||
"_class": "com.securityc4po.api.finding.FindingEntity"
|
|
||||||
},{
|
|
||||||
"_id": {
|
|
||||||
"$oid": "637606830687d905ca60af1d"
|
|
||||||
},
|
|
||||||
"lastModified": {
|
|
||||||
"$date": {
|
|
||||||
"$numberLong": "1668679299814"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"data": {
|
|
||||||
"_id": "bddf810b-f20e-473e-a63d-34fcba7e48ef",
|
|
||||||
"severity": "CRITICAL",
|
|
||||||
"title": "Login SQL Injection ",
|
|
||||||
"description": "Inside Login Form using the ' or TRUE-- Syntax will enable the user to login as the Admin.",
|
|
||||||
"impact": "Active User Session with Admin priviledges can affect the whole application.",
|
|
||||||
"affectedUrls": [
|
|
||||||
"http://localhost:3000/#/login"
|
|
||||||
],
|
|
||||||
"reproduction": "Step 1:\nGo to login page.\n\nStep 2:\nEnter ' or TRUE-- in the username field and enter a random password.",
|
|
||||||
"mitigation": ""
|
|
||||||
},
|
|
||||||
"_class": "com.securityc4po.api.finding.FindingEntity"
|
|
||||||
},{
|
|
||||||
"_id": {
|
|
||||||
"$oid": "637612280687d905ca60af20"
|
|
||||||
},
|
|
||||||
"lastModified": {
|
|
||||||
"$date": {
|
|
||||||
"$numberLong": "1668682280551"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"data": {
|
|
||||||
"_id": "d7c95af7-5434-4768-b62c-5b11f9396276",
|
|
||||||
"severity": "MEDIUM",
|
|
||||||
"title": "Searchbar XSS",
|
|
||||||
"description": "Adding <iframe> in the search bar of the header results in XSS Vuln.",
|
|
||||||
"impact": "This impacts the Webapplication",
|
|
||||||
"affectedUrls": [
|
|
||||||
"http://localhost:3000/#/search?q=%3Ciframe%20src%3D%22javascript:alert(%60xss%60)%22%3E"
|
|
||||||
],
|
|
||||||
"reproduction": "Step 1: \nClick on search bar of header.\n\nStep 2: \nEnter <iframe src=\"javascript:alert(`xss`)\">\n\nStep3: Press ENTER\n\nYou will now get a PopUp because the javascript code was executed inside the browser.",
|
|
||||||
"mitigation": "Sanitse Input Field."
|
|
||||||
},
|
|
||||||
"_class": "com.securityc4po.api.finding.FindingEntity"
|
|
||||||
},{
|
|
||||||
"_id": {
|
|
||||||
"$oid": "63776860fcdda12bf2e51eb2"
|
|
||||||
},
|
|
||||||
"lastModified": {
|
|
||||||
"$date": {
|
|
||||||
"$numberLong": "1670489874240"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"data": {
|
|
||||||
"_id": "cb33fad4-7965-4654-a9f9-f007edaca35c",
|
|
||||||
"severity": "HIGH",
|
|
||||||
"title": "Searchbar XSS",
|
|
||||||
"description": "Adding <iframe src=\"javascript:alert('xss')\"> in the search bar of the header results in XSS Vuln.",
|
|
||||||
"impact": "This impacts the Webbapp.",
|
|
||||||
"affectedUrls": [
|
|
||||||
"http://localhost:3000/#/search?q=%3Ciframe%20src%3D%22javascript:alert('xss')%22%3E"
|
|
||||||
],
|
|
||||||
"reproduction": "Step1: \nClick on search field of the header\n\nStep 2: \nEnter <iframe src=\"javascript:alert('xss')\">\n\nStep 3: \nPress ENTER\n\nYou will now get a PopUp",
|
|
||||||
"mitigation": "Sanitise Input Fields."
|
|
||||||
},
|
|
||||||
"_class": "com.securityc4po.api.finding.FindingEntity"
|
|
||||||
},{
|
|
||||||
"_id": {
|
|
||||||
"$oid": "6391a364aceddd4dd1b32322"
|
|
||||||
},
|
|
||||||
"lastModified": {
|
|
||||||
"$date": {
|
|
||||||
"$numberLong": "1670488932489"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"data": {
|
|
||||||
"_id": "b6dfddde-9bc2-4658-8c18-668190053105",
|
|
||||||
"severity": "CRITICAL",
|
|
||||||
"title": "Searchbar XSS",
|
|
||||||
"description": "Adding <iframe src=\"javascript:alert('xss')\"> in the search bar of the header results in XSS Vuln.",
|
|
||||||
"impact": "This impacts the Webbapp.",
|
|
||||||
"affectedUrls": [
|
|
||||||
"http://localhost:3000/#/search?q=%3Ciframe%20src%3D%22javascript:alert('xss')%22%3E"
|
|
||||||
],
|
|
||||||
"reproduction": "Step1: \nClick on search field of the header\n\nStep 2: \nEnter <iframe src=\"javascript:alert('xss')\">\n\nStep 3: \nPress ENTER\n\nYou will now get a PopUp",
|
|
||||||
"mitigation": "Sanitise Input Fields."
|
|
||||||
},
|
|
||||||
"_class": "com.securityc4po.api.finding.FindingEntity"
|
|
||||||
},{
|
|
||||||
"_id": {
|
|
||||||
"$oid": "6391a39baceddd4dd1b32323"
|
|
||||||
},
|
|
||||||
"lastModified": {
|
|
||||||
"$date": {
|
|
||||||
"$numberLong": "1670488987700"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"data": {
|
|
||||||
"_id": "e9a50c5d-e9ea-4596-b1a9-8ad67eddef04",
|
|
||||||
"severity": "CRITICAL",
|
|
||||||
"title": "Searchbar XSS",
|
|
||||||
"description": "Adding <iframe src=\"javascript:alert('xss')\"> in the search bar of the header results in XSS Vuln.",
|
|
||||||
"impact": "This impacts the Webbapp.",
|
|
||||||
"affectedUrls": [
|
|
||||||
"http://localhost:3000/#/search?q=%3Ciframe%20src%3D%22javascript:alert('xss')%22%3E"
|
|
||||||
],
|
|
||||||
"reproduction": "Step1: \nClick on search field of the header\n\nStep 2: \nEnter <iframe src=\"javascript:alert('xss')\">\n\nStep 3: \nPress ENTER\n\nYou will now get a PopUp",
|
|
||||||
"mitigation": "Sanitise Input Fields."
|
|
||||||
},
|
|
||||||
"_class": "com.securityc4po.api.finding.FindingEntity"
|
|
||||||
},{
|
|
||||||
"_id": {
|
|
||||||
"$oid": "6391a3cbaceddd4dd1b32324"
|
|
||||||
},
|
|
||||||
"lastModified": {
|
|
||||||
"$date": {
|
|
||||||
"$numberLong": "1670489035954"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"data": {
|
|
||||||
"_id": "7f51e615-230f-4f90-a671-13e66e82370f",
|
|
||||||
"severity": "CRITICAL",
|
|
||||||
"title": "Searchbar XSS",
|
|
||||||
"description": "Adding <iframe src=\"javascript:alert('xss')\"> in the search bar of the header results in XSS Vuln.",
|
|
||||||
"impact": "This impacts the Webbapp.",
|
|
||||||
"affectedUrls": [
|
|
||||||
"http://localhost:3000/#/search?q=%3Ciframe%20src%3D%22javascript:alert('xss')%22%3E"
|
|
||||||
],
|
|
||||||
"reproduction": "Step1: \nClick on search field of the header\n\nStep 2: \nEnter <iframe src=\"javascript:alert('xss')\">\n\nStep 3: \nPress ENTER\n\nYou will now get a PopUp",
|
|
||||||
"mitigation": "Sanitise Input Fields."
|
|
||||||
},
|
|
||||||
"_class": "com.securityc4po.api.finding.FindingEntity"
|
|
||||||
}]
|
}]
|
File diff suppressed because it is too large
Load Diff
|
@ -1,351 +1,269 @@
|
||||||
[{
|
[{
|
||||||
"_id": {
|
"_id": {
|
||||||
"$oid": "62f3c50c7acde34f740ba737"
|
"$oid": "6405d84a13ae975803a098fa"
|
||||||
},
|
},
|
||||||
"lastModified": {
|
"lastModified": {
|
||||||
"$date": {
|
"$date": {
|
||||||
"$numberLong": "1668425376081"
|
"$numberLong": "1678109612474"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"data": {
|
"data": {
|
||||||
"_id": "5a4f126c-9471-43b8-80b9-6eb02b7c35d0",
|
"_id": "575dd9d4-cb3c-4df3-981e-8a18bf8dc1d2",
|
||||||
"client": "Dio Stonemask Inc.",
|
"client": "Dio Stonemask Inc.",
|
||||||
"title": "log4jj bizarre adventure",
|
"title": "log4jj bizarre adventure",
|
||||||
"createdAt": "2022-08-10T14:47:40.140406Z",
|
"createdAt": "2023-03-06T12:10:50.835664Z",
|
||||||
"tester": "Jojo",
|
"tester": "Jojo",
|
||||||
|
"summary": "This report includes an Executeive Summary, the rules in regards to the scope of the pentest and the choosen approach of the pentester.\nDio Stonemask Inc. contracted Jojo to perform a Penetration Test to identify security weaknesses,\ndetermine the impact to Dio Stonemask Inc., document all findings in a clear and repeatable manner,\nand provide remediation recommendations",
|
||||||
"projectPentests": [
|
"projectPentests": [
|
||||||
{
|
{
|
||||||
"pentestId": "11601f51-bc17-47fd-847d-0c53df5405b5",
|
"pentestId": "54f3ce12-784a-4e44-b9b3-0a986119ec50",
|
||||||
"status": "IN_PROGRESS"
|
"status": "COMPLETED"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"pentestId": "9a073a08-e4fc-4450-8202-c902455b66ec",
|
"pentestId": "d724df75-e85a-4124-a5be-bccadc78beaf",
|
||||||
"status": "OPEN"
|
"status": "PAUSED"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"pentestId": "981c5e24-7276-47f8-a821-ff5976292ad4",
|
"pentestId": "c9c1c2f4-14dd-43f4-bc0d-bac03755f798",
|
||||||
"status": "OPEN"
|
"status": "PAUSED"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"pentestId": "2d46a183-8f11-4fbc-bbf1-e439f7282bb9",
|
"pentestId": "288599c2-c295-4825-b1ff-db20e99f45ba",
|
||||||
"status": "OPEN"
|
"status": "PAUSED"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"pentestId": "eb4f80f3-caac-4fef-a5dd-53616701f171",
|
"pentestId": "7c1c1d64-000d-461b-b60f-50bfc70868e6",
|
||||||
"status": "OPEN"
|
"status": "PAUSED"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"pentestId": "0ab8de31-9d5e-4b6b-a43c-12207c160863",
|
"pentestId": "415528d1-a92c-4e14-adf1-2846b2ce0f70",
|
||||||
"status": "IN_PROGRESS"
|
"status": "PAUSED"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"pentestId": "3ed9e894-58e8-46b9-9859-cde675fec17c",
|
"pentestId": "8d91e25f-eaeb-42f6-800c-4e7113656321",
|
||||||
"status": "OPEN"
|
"status": "PAUSED"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"pentestId": "53fdab75-ea52-4cea-85ed-df8b67f41b72",
|
"pentestId": "ed9595bb-cc80-4daa-873e-e7470fc0b7d1",
|
||||||
"status": "OPEN"
|
"status": "PAUSED"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"pentestId": "6270d4bc-5f39-4358-ad0a-fd5791191f28",
|
"pentestId": "35481ca5-5672-4a11-a2b8-38ece069ca70",
|
||||||
"status": "IN_PROGRESS"
|
"status": "PAUSED"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"pentestId": "1a90f468-470a-4b1e-9783-cc761b1770ee",
|
"pentestId": "538f8e15-8d0e-43ac-b7a6-d6b5959581eb",
|
||||||
"status": "OPEN"
|
"status": "PAUSED"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"pentestId": "6eb37869-baef-4a5b-9ac0-bf202a49874f",
|
"pentestId": "3bff597e-d680-4b87-8352-be32f40db074",
|
||||||
"status": "OPEN"
|
"status": "PAUSED"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"pentestId": "da89c933-1413-4186-ad2c-f1967cb8dbb4",
|
"pentestId": "27ca5852-aa9f-44ed-b2fe-c46c31b415f4",
|
||||||
"status": "OPEN"
|
"status": "PAUSED"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"pentestId": "b3682591-f6c3-4969-bf15-69f4d495ef18",
|
"pentestId": "60cf0cf9-f62a-4669-87a7-f519e7be0613",
|
||||||
"status": "OPEN"
|
"status": "PAUSED"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"pentestId": "9e8e2736-afc9-4f63-b29f-567f9f316c83",
|
"pentestId": "05251dfd-a382-47af-85d5-798dd1a6171a",
|
||||||
"status": "OPEN"
|
"status": "PAUSED"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"pentestId": "3405bdd6-1ae2-4876-9c18-443a791cec9c",
|
"pentestId": "be6780a2-b66e-42a6-a725-805633589921",
|
||||||
"status": "OPEN"
|
"status": "PAUSED"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"pentestId": "2fd387b3-b7a5-4297-9790-5d7845214c05",
|
"pentestId": "192b9fed-596b-4345-b33d-ca3882ba9bdd",
|
||||||
"status": "OPEN"
|
"status": "PAUSED"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"pentestId": "a61116c5-1859-4df3-8252-7788c31472d8",
|
"pentestId": "6d3f0b58-b311-465e-9f01-e3e45d165902",
|
||||||
"status": "OPEN"
|
"status": "PAUSED"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"pentestId": "47d8b39d-9fa7-4772-8605-84aa0531f49e",
|
"pentestId": "058dd5c7-63a5-40cb-a4ed-46e5cdcb87ff",
|
||||||
"status": "OPEN"
|
"status": "PAUSED"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"pentestId": "bd2b8899-0cd9-41fd-a975-257aac48b81f",
|
"pentestId": "36e1c198-d425-4a38-ad0b-2f9d6759931e",
|
||||||
"status": "OPEN"
|
"status": "PAUSED"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"pentestId": "b9bde632-c275-4566-b693-c57a3dad47f3",
|
"pentestId": "b3063d09-237f-493e-b0db-603a11829d88",
|
||||||
"status": "OPEN"
|
"status": "PAUSED"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"pentestId": "32cc5c4e-7234-42b7-8031-c2e231bc0404",
|
"pentestId": "6ae89321-678f-4191-b008-8abfc42401c3",
|
||||||
"status": "OPEN"
|
"status": "PAUSED"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"pentestId": "07e34e95-7dda-499a-8be8-0e8378f0e0d0",
|
"pentestId": "3334d254-87bf-4115-8d88-e2fed022ad06",
|
||||||
"status": "OPEN"
|
"status": "PAUSED"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"pentestId": "b70f6720-ee17-49d6-8838-bd776cd18d0a",
|
"pentestId": "8e97f1e0-b02c-4be2-b30e-372d09614038",
|
||||||
"status": "OPEN"
|
"status": "PAUSED"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"pentestId": "9fb260ea-333f-44c6-884b-e46352564e2a",
|
"pentestId": "e9c9eecb-116b-4a8c-ac8c-4a279f77e1f4",
|
||||||
"status": "OPEN"
|
"status": "PAUSED"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"pentestId": "87f492f7-991b-4e04-9531-5dba0bc34b1b",
|
"pentestId": "f0531d71-18d3-41a7-a37a-2c15f6b26dcb",
|
||||||
"status": "OPEN"
|
"status": "PAUSED"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"pentestId": "6d846445-d470-447a-96b3-8f4b57df3221",
|
"pentestId": "d73543ef-a66f-4878-9ecb-ab5207ed734f",
|
||||||
"status": "OPEN"
|
"status": "PAUSED"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"pentestId": "123c43ae-6870-4883-a1c5-2f99946e2c2d",
|
"pentestId": "22130f1e-53c2-404b-8f77-750e82d12768",
|
||||||
"status": "OPEN"
|
"status": "PAUSED"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"pentestId": "8be5b377-3eb0-4b54-81d2-8cfd5ea1f0f1",
|
"pentestId": "54db12f1-1fdc-48f9-9b1d-b6b1fb39bc07",
|
||||||
"status": "OPEN"
|
"status": "PAUSED"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"pentestId": "6b1d2b71-9e31-4e78-a82e-5325c699658c",
|
"pentestId": "7853a95c-7ee3-4b31-af18-401c104efc7e",
|
||||||
"status": "OPEN"
|
"status": "PAUSED"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"pentestId": "77e765ef-40fb-4b6e-9d80-1e06cae7d4a3",
|
"pentestId": "7ca78e39-7d4c-46c5-a9c3-ba58c7fba844",
|
||||||
"status": "OPEN"
|
"status": "PAUSED"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"pentestId": "5821cd2c-aa17-4339-b697-1b4089d3bf93",
|
"pentestId": "dca5b8b3-e994-4d5c-8740-b21ee806a4e5",
|
||||||
"status": "OPEN"
|
"status": "PAUSED"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"pentestId": "bb57b94f-c8bc-4dd9-b4bf-e14d0a97cc31",
|
"pentestId": "5e7b999c-e878-4d48-9ce8-9b65ef578dae",
|
||||||
"status": "OPEN"
|
"status": "PAUSED"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"pentestId": "a5e3aaba-268e-4a40-92f9-05c0dae4cc0f",
|
"pentestId": "8bc131f4-b9c8-4dd5-927b-0675dff6344e",
|
||||||
"status": "OPEN"
|
"status": "PAUSED"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"pentestId": "18ed1ddb-524a-4333-af90-7716bd51dc7b",
|
"pentestId": "ed134842-6578-4d22-af57-282161c5306b",
|
||||||
"status": "OPEN"
|
"status": "PAUSED"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"pentestId": "c2d19d1e-39e5-4862-82c9-d88c5d91f630",
|
"pentestId": "f35f30fb-f246-4a1f-ae26-ce864647a341",
|
||||||
"status": "OPEN"
|
"status": "PAUSED"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"pentestId": "728e294f-e27d-4bef-903b-d9eeb54cf086",
|
"pentestId": "47021e69-95ab-4d93-ac13-aac0379ca809",
|
||||||
"status": "OPEN"
|
"status": "PAUSED"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"pentestId": "91cd7aee-acda-4c95-ba35-16932448f29f",
|
"pentestId": "f19a5176-64bc-452b-aa63-8861aab75059",
|
||||||
"status": "OPEN"
|
"status": "PAUSED"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"pentestId": "e496d9ba-7775-479e-8904-864c04fec3f9",
|
"pentestId": "c60ac6e5-39e8-4fae-8d65-d71ea69a2404",
|
||||||
"status": "OPEN"
|
"status": "PAUSED"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"pentestId": "ee87e923-63d7-40bc-b41e-049fe087e1dd",
|
"pentestId": "2764e64b-0a7e-456c-9999-cdd05c5ef50b",
|
||||||
"status": "OPEN"
|
"status": "PAUSED"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"pentestId": "cbe94eaf-c734-4d6f-96ec-7d84a4a5b5cc",
|
"pentestId": "1247dd20-2986-4887-9c17-74806ce56eef",
|
||||||
"status": "IN_PROGRESS"
|
"status": "PAUSED"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"pentestId": "c9ecfc9f-23f1-4744-a578-54b0c96a9e87",
|
"pentestId": "e01d1a34-15fa-4f29-8054-8209a422e505",
|
||||||
"status": "IN_PROGRESS"
|
"status": "PAUSED"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"pentestId": "ca0c10a1-8fcc-4b0b-98c0-2403709d7e50",
|
"pentestId": "c55343b0-c99c-4bfd-8f30-b8464b442dad",
|
||||||
"status": "OPEN"
|
"status": "PAUSED"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"pentestId": "bce6f266-2c70-4e45-a1db-d767e4bcc1f8",
|
"pentestId": "47ff61bb-2e4f-45e3-9630-136f9d704882",
|
||||||
"status": "OPEN"
|
"status": "PAUSED"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"pentestId": "be0b07a3-64e4-4122-a362-dd657b8b6b0a",
|
"pentestId": "0b353e67-3092-4586-9558-172354beaf8b",
|
||||||
"status": "OPEN"
|
"status": "PAUSED"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"pentestId": "8f2230fb-bd5c-4047-9db6-74bc49be9cc1",
|
"pentestId": "5804e2ce-8c5b-4f3d-8674-433042e61a7f",
|
||||||
"status": "OPEN"
|
"status": "PAUSED"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"pentestId": "a1b00a90-cb14-475f-ba3a-5807a21df704",
|
"pentestId": "4fc1260b-8b5b-47a7-bdee-61261e23919d",
|
||||||
"status": "OPEN"
|
"status": "PAUSED"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"pentestId": "af2e7766-ecd1-4015-b4e1-c0b978643a0f",
|
"pentestId": "39dfbf25-e97d-4bd8-9943-a9eec183bfcf",
|
||||||
"status": "OPEN"
|
"status": "PAUSED"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"pentestId": "27b64044-b3ff-48bf-9220-837b420f3904",
|
"pentestId": "53668fb6-471d-4363-9e47-8f73e4f1a7d4",
|
||||||
"status": "OPEN"
|
"status": "PAUSED"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"pentestId": "b5eb1683-700a-4522-8b53-45809e665643",
|
"pentestId": "86637ffd-8e6e-4e00-9179-42f52780427a",
|
||||||
"status": "OPEN"
|
"status": "PAUSED"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"pentestId": "86b4d382-e433-4bac-ab6e-530a0dce299d",
|
"pentestId": "04f9532e-3c05-4eff-9e9f-b2d733a14a77",
|
||||||
"status": "OPEN"
|
"status": "PAUSED"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"pentestId": "7a118a29-f983-4219-834c-f01554231910",
|
"pentestId": "1e58f29e-81fb-48d2-94bf-7b89e227f590",
|
||||||
"status": "OPEN"
|
"status": "PAUSED"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"pentestId": "ac9bc697-a53f-4278-98b9-05d8ba19a50d",
|
"pentestId": "2c78589b-558e-4b99-a182-df4df3c1439b",
|
||||||
"status": "OPEN"
|
"status": "PAUSED"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"pentestId": "13cecebb-321a-4ef8-8116-f6814652f7d7",
|
"pentestId": "9383b9c1-6c2e-422b-b16f-31a9640d1647",
|
||||||
"status": "OPEN"
|
"status": "PAUSED"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"pentestId": "048287bc-c41b-49a1-aeb5-2cc98a5bad06",
|
"pentestId": "2f87faf9-611f-40ae-9c0e-412d0bfd0481",
|
||||||
"status": "OPEN"
|
"status": "PAUSED"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"pentestId": "4d1b424e-05ea-468c-9902-3626a79ccfe6",
|
"pentestId": "0f47fcbc-f567-4009-ae56-a894cf17cc46",
|
||||||
"status": "OPEN"
|
"status": "PAUSED"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"pentestId": "377d73b8-f8da-461e-909b-524a38a37ed6",
|
"pentestId": "ba0fa19c-5533-4be8-8169-9ffa7d449ab0",
|
||||||
"status": "OPEN"
|
"status": "PAUSED"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"pentestId": "16e10ad9-f49d-4a74-9de7-10a49e2401e2",
|
"pentestId": "0f47ac3b-d19a-4115-9ddf-dc9b2f11abae",
|
||||||
"status": "OPEN"
|
"status": "PAUSED"
|
||||||
},
|
|
||||||
{
|
|
||||||
"pentestId": "4c68c22e-6073-4ec8-aebb-45ad2a3cc848",
|
|
||||||
"status": "OPEN"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"pentestId": "276e5823-b517-445c-b182-e6eda6478d44",
|
|
||||||
"status": "OPEN"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"pentestId": "84c661c0-2775-440a-97c5-ff35f345cabb",
|
|
||||||
"status": "OPEN"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"pentestId": "fb6d909c-8d16-48e3-b0e5-aba9bf3e8eae",
|
|
||||||
"status": "OPEN"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"pentestId": "0b211e22-dd63-46cc-a12f-be7ac73d7a64",
|
|
||||||
"status": "OPEN"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"pentestId": "63310549-e2a8-4dd0-a91a-9cfa06e2dc41",
|
|
||||||
"status": "OPEN"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"pentestId": "ac8d52d0-f0c8-47ec-ab13-24f40dc4f9e6",
|
|
||||||
"status": "OPEN"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"pentestId": "3ddc4950-f662-4ec1-9a04-b9c3591d8b06",
|
|
||||||
"status": "OPEN"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"pentestId": "4c11d176-2ec5-4ed9-9c8a-c1edd33b262c",
|
|
||||||
"status": "OPEN"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"pentestId": "b9a6f4ba-62e6-442b-a274-b3ffe209d248",
|
|
||||||
"status": "OPEN"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"pentestId": "705e28a2-b0a4-4b8c-9922-10c5c67faf65",
|
|
||||||
"status": "OPEN"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"pentestId": "4c59259d-4a24-43ef-8738-fe214e0b0673",
|
|
||||||
"status": "OPEN"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"pentestId": "a7ab3344-db7d-495a-8e55-dd572ea7c5e0",
|
|
||||||
"status": "OPEN"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"pentestId": "195e7f58-a7b2-4571-9c66-1e91a0dfca28",
|
|
||||||
"status": "OPEN"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"pentestId": "543a9768-4e5c-4c70-9aae-977afa542afa",
|
|
||||||
"status": "OPEN"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"pentestId": "a17516de-e92a-43b9-a415-203dce48fb0e",
|
|
||||||
"status": "OPEN"
|
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"createdBy": "3c4ae87f-0d56-4634-a824-b4883c403c8a"
|
"createdBy": "ce650edd-aebc-4478-9e17-40545ff66280"
|
||||||
},
|
},
|
||||||
"_class": "com.securityc4po.api.project.ProjectEntity"
|
"_class": "com.securityc4po.api.project.ProjectEntity"
|
||||||
},{
|
},{
|
||||||
"_id": {
|
"_id": {
|
||||||
"$oid": "62f3c5317acde34f740ba738"
|
"$oid": "6405e92813ae975803a09905"
|
||||||
},
|
},
|
||||||
"lastModified": {
|
"lastModified": {
|
||||||
"$date": {
|
"$date": {
|
||||||
"$numberLong": "1660142897912"
|
"$numberLong": "1678108968564"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"data": {
|
"data": {
|
||||||
"_id": "42b8c0df-b70e-4526-8ed0-7c022195fe85",
|
"_id": "d6e83738-4251-44ac-ad40-21b360780c98",
|
||||||
"client": "Allsafe",
|
"client": "Allsafe",
|
||||||
"title": "CashMyData (iOS)",
|
"title": "CashMyData (iOS)",
|
||||||
"createdAt": "2022-08-10T14:48:17.912592Z",
|
"createdAt": "2023-03-06T13:22:48.564351Z",
|
||||||
"tester": "Elliot",
|
"tester": "Elliot",
|
||||||
"projectPentests": [],
|
"projectPentests": [],
|
||||||
"createdBy": "6740ad72-8f42-486a-bcf3-e057e6afb0de"
|
"createdBy": "5f104d76-bd8d-4258-852a-d000c7f0666d"
|
||||||
},
|
|
||||||
"_class": "com.securityc4po.api.project.ProjectEntity"
|
|
||||||
},{
|
|
||||||
"_id": {
|
|
||||||
"$oid": "62ff7534ac2b4d14d86215c4"
|
|
||||||
},
|
|
||||||
"lastModified": {
|
|
||||||
"$date": {
|
|
||||||
"$numberLong": "1660908852340"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"data": {
|
|
||||||
"_id": "195809ed-9722-4ad5-a84b-0099a9a01652",
|
|
||||||
"client": "Novatec",
|
|
||||||
"title": "log4j pentest",
|
|
||||||
"createdAt": "2022-08-19T11:34:12.339990Z",
|
|
||||||
"tester": "Stipe",
|
|
||||||
"projectPentests": [],
|
|
||||||
"createdBy": "7fe49c8d-fee3-47e0-9224-94e0ac7436c6"
|
|
||||||
},
|
},
|
||||||
"_class": "com.securityc4po.api.project.ProjectEntity"
|
"_class": "com.securityc4po.api.project.ProjectEntity"
|
||||||
}]
|
}]
|
|
@ -106,7 +106,7 @@
|
||||||
"bearer": [
|
"bearer": [
|
||||||
{
|
{
|
||||||
"key": "token",
|
"key": "token",
|
||||||
"value": "eyJhbGciOiJSUzI1NiIsInR5cCIgOiAiSldUIiwia2lkIiA6ICItdG1lbEV0ZHhGTnRSMW9aNXlRdE5jaFFpX0RVN2VNeV9YcU44aXY0S3hzIn0.eyJleHAiOjE2NzY5ODY0NTgsImlhdCI6MTY3Njk4NjE1OCwianRpIjoiMzk2NjcwM2UtMTk4My00MWU4LTkyNjAtYjhmNDExOWRmYzYwIiwiaXNzIjoiaHR0cDovL2xvY2FsaG9zdDo4MDgwL2F1dGgvcmVhbG1zL2M0cG9fcmVhbG1fbG9jYWwiLCJhdWQiOiJhY2NvdW50Iiwic3ViIjoiMTBlMDZkN2EtOGRkMC00ZWNkLTg5NjMtMDU2YjQ1MDc5YzRmIiwidHlwIjoiQmVhcmVyIiwiYXpwIjoiYzRwb19sb2NhbCIsInNlc3Npb25fc3RhdGUiOiIxZDBmMTk4YS03MTg5LTQ4ZmItYWQ0Ny00NTllNjVkOWU3ZjciLCJhbGxvd2VkLW9yaWdpbnMiOlsiKiJdLCJyZWFsbV9hY2Nlc3MiOnsicm9sZXMiOlsiYzRwb191c2VyIiwib2ZmbGluZV9hY2Nlc3MiLCJ1bWFfYXV0aG9yaXphdGlvbiJdfSwicmVzb3VyY2VfYWNjZXNzIjp7ImM0cG9fbG9jYWwiOnsicm9sZXMiOlsidXNlciJdfSwiYWNjb3VudCI6eyJyb2xlcyI6WyJtYW5hZ2UtYWNjb3VudCIsIm1hbmFnZS1hY2NvdW50LWxpbmtzIiwidmlldy1wcm9maWxlIl19fSwic2NvcGUiOiJwcm9maWxlIGVtYWlsIiwic2lkIjoiMWQwZjE5OGEtNzE4OS00OGZiLWFkNDctNDU5ZTY1ZDllN2Y3IiwiZW1haWxfdmVyaWZpZWQiOmZhbHNlLCJuYW1lIjoidGVzdCB1c2VyIiwicHJlZmVycmVkX3VzZXJuYW1lIjoidHR0IiwiZ2l2ZW5fbmFtZSI6InRlc3QiLCJmYW1pbHlfbmFtZSI6InVzZXIifQ.m1aOgFK_8ADYS6EdPLWT_wQNTsptSM9XipQQcttSd1lZKdZu6FgFVRSsW39fdgVLGurKxaglGoNgsywGDeomPS7hJuowzmYIEoDZr13MXCBqX9-YAsEDbwvrGcUI4jVXwKl8E-rTLpl3c5Ckj4tbDeUD3EuLk7yTYbkUnijqwsFlZpwJ_gbjZAfNiZCZpJlvh95cQKvFBbyzP7sfxkYikzpxY-1UHSUpoHBxJaOcJ6hoh-PIQVUw-8mvuoOyd5dMmavl5njvijr716_2loj6B6YHLueHIGlenI5Aob9DEOcL17SXivvcEyM5xTKyfqx3Jt1XY7jQ8mOIT4_iqxTc_w",
|
"value": "eyJhbGciOiJSUzI1NiIsInR5cCIgOiAiSldUIiwia2lkIiA6ICItdG1lbEV0ZHhGTnRSMW9aNXlRdE5jaFFpX0RVN2VNeV9YcU44aXY0S3hzIn0.eyJleHAiOjE2NzgyNjg2NTksImlhdCI6MTY3ODI2ODM1OSwianRpIjoiNTkzODgzZWYtZDZkZS00MGJjLWE3MGQtMTU5MDE3YzBlY2Q4IiwiaXNzIjoiaHR0cDovL2xvY2FsaG9zdDo4MDgwL2F1dGgvcmVhbG1zL2M0cG9fcmVhbG1fbG9jYWwiLCJhdWQiOiJhY2NvdW50Iiwic3ViIjoiMTBlMDZkN2EtOGRkMC00ZWNkLTg5NjMtMDU2YjQ1MDc5YzRmIiwidHlwIjoiQmVhcmVyIiwiYXpwIjoiYzRwb19sb2NhbCIsInNlc3Npb25fc3RhdGUiOiIxNGUwNzYwNy02YTUyLTRmZTItODA0MC00Zjc4NDc4ZjI3ZGQiLCJhbGxvd2VkLW9yaWdpbnMiOlsiKiJdLCJyZWFsbV9hY2Nlc3MiOnsicm9sZXMiOlsiYzRwb191c2VyIiwib2ZmbGluZV9hY2Nlc3MiLCJ1bWFfYXV0aG9yaXphdGlvbiJdfSwicmVzb3VyY2VfYWNjZXNzIjp7ImM0cG9fbG9jYWwiOnsicm9sZXMiOlsidXNlciJdfSwiYWNjb3VudCI6eyJyb2xlcyI6WyJtYW5hZ2UtYWNjb3VudCIsIm1hbmFnZS1hY2NvdW50LWxpbmtzIiwidmlldy1wcm9maWxlIl19fSwic2NvcGUiOiJwcm9maWxlIGVtYWlsIiwic2lkIjoiMTRlMDc2MDctNmE1Mi00ZmUyLTgwNDAtNGY3ODQ3OGYyN2RkIiwiZW1haWxfdmVyaWZpZWQiOmZhbHNlLCJuYW1lIjoidGVzdCB1c2VyIiwicHJlZmVycmVkX3VzZXJuYW1lIjoidHR0IiwiZ2l2ZW5fbmFtZSI6InRlc3QiLCJmYW1pbHlfbmFtZSI6InVzZXIifQ.gHG1z-amLiv4mv6DujwEMPIjfn8ojROSmypOG4_A2GvF6ekmSi36WQO8I2IjPJZ4XB1amKgeG5pAI6I4AYU8DwYIOsDrqKgPSitDEyY9lCjUtxFHZpmemkQljdJw3UNjDKgDuyYpu-lPcapcEwN75BeSxmnkNVQ7ri3dLHf5AhLlQExlVD0ts4ux4kQ4X82cn_iPGRa869jZEWbVHKnhZaHufsA0444qgw45mBJu1ycG7_4VzKmoeprSV5RSH_DxMMZaDCUb0_Xf1QZ58VVEpjW1WRNvvAip5uVNnyduQe2SJ7TlZqNy5DzDyzBko8d4LnWjE_-qdo4JmwztApkOww",
|
||||||
"type": "string"
|
"type": "string"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -124,7 +124,7 @@
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"url": {
|
"url": {
|
||||||
"raw": "http://localhost:8444/reports/5a4f126c-9471-43b8-80b9-6eb02b7c35d0/pdf",
|
"raw": "http://localhost:8444/reports/575dd9d4-cb3c-4df3-981e-8a18bf8dc1d2/pdf",
|
||||||
"protocol": "http",
|
"protocol": "http",
|
||||||
"host": [
|
"host": [
|
||||||
"localhost"
|
"localhost"
|
||||||
|
@ -132,7 +132,7 @@
|
||||||
"port": "8444",
|
"port": "8444",
|
||||||
"path": [
|
"path": [
|
||||||
"reports",
|
"reports",
|
||||||
"5a4f126c-9471-43b8-80b9-6eb02b7c35d0",
|
"575dd9d4-cb3c-4df3-981e-8a18bf8dc1d2",
|
||||||
"pdf"
|
"pdf"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,5 +4,7 @@ data class Comment (
|
||||||
val id: String,
|
val id: String,
|
||||||
val title: String,
|
val title: String,
|
||||||
val description: String,
|
val description: String,
|
||||||
val relatedFindings: List<String>? = emptyList()
|
val relatedFindings: List<String>? = emptyList(),
|
||||||
|
// List of attachment id's for file upload
|
||||||
|
val attachments: List<String>? = emptyList()
|
||||||
)
|
)
|
||||||
|
|
|
@ -8,7 +8,9 @@ data class Finding (
|
||||||
val impact: String,
|
val impact: String,
|
||||||
val affectedUrls: List<String>? = emptyList(),
|
val affectedUrls: List<String>? = emptyList(),
|
||||||
val reproduction: String,
|
val reproduction: String,
|
||||||
val mitigation: String?
|
val mitigation: String?,
|
||||||
|
// List of attachment id's for file upload
|
||||||
|
val attachments: List<String>? = emptyList()
|
||||||
)
|
)
|
||||||
|
|
||||||
enum class Severity {
|
enum class Severity {
|
||||||
|
|
|
@ -3,7 +3,7 @@ package com.securityc4po.reporting.remote.model.api
|
||||||
enum class PentestStatus {
|
enum class PentestStatus {
|
||||||
NOT_STARTED,
|
NOT_STARTED,
|
||||||
DISABLED,
|
DISABLED,
|
||||||
OPEN,
|
PAUSED,
|
||||||
IN_PROGRESS,
|
IN_PROGRESS,
|
||||||
COMPLETED
|
COMPLETED
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,7 +12,7 @@ data class Project(
|
||||||
val title: String,
|
val title: String,
|
||||||
val createdAt: String,
|
val createdAt: String,
|
||||||
val tester: String,
|
val tester: String,
|
||||||
val summary: String? = null,
|
val summary: String? = "",
|
||||||
var projectPentests: List<ProjectPentest>? = emptyList(),
|
var projectPentests: List<ProjectPentest>? = emptyList(),
|
||||||
val createdBy: String
|
val createdBy: String
|
||||||
)
|
)
|
||||||
|
|
Binary file not shown.
|
@ -0,0 +1,94 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<!-- Created with Jaspersoft Studio version 6.20.0.final using JasperReports Library version 6.20.0-2bc7ab61c56f459e8176eb05c7705e145cd400ad -->
|
||||||
|
<jasperReport xmlns="http://jasperreports.sourceforge.net/jasperreports" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://jasperreports.sourceforge.net/jasperreports http://jasperreports.sourceforge.net/xsd/jasperreport.xsd" name="CommentsSubreport" pageWidth="595" pageHeight="842" columnWidth="555" leftMargin="20" rightMargin="20" topMargin="20" bottomMargin="20" uuid="2d64b016-bc6c-4109-8b3a-f9f818c7397d">
|
||||||
|
<property name="com.jaspersoft.studio.data.defaultdataadapter" value="ProjectReportJasperData Template JSON Adapter"/>
|
||||||
|
<queryString language="json">
|
||||||
|
<![CDATA[projectReportData.projectPentestReport.comments]]>
|
||||||
|
</queryString>
|
||||||
|
<field name="id" class="java.lang.String">
|
||||||
|
<property name="net.sf.jasperreports.json.field.expression" value="id"/>
|
||||||
|
<fieldDescription><![CDATA[id]]></fieldDescription>
|
||||||
|
</field>
|
||||||
|
<field name="title" class="java.lang.String">
|
||||||
|
<property name="net.sf.jasperreports.json.field.expression" value="title"/>
|
||||||
|
<fieldDescription><![CDATA[title]]></fieldDescription>
|
||||||
|
</field>
|
||||||
|
<field name="description" class="java.lang.String">
|
||||||
|
<property name="net.sf.jasperreports.json.field.expression" value="description"/>
|
||||||
|
<fieldDescription><![CDATA[description]]></fieldDescription>
|
||||||
|
</field>
|
||||||
|
<field name="attachments" class="java.util.ArrayList"/>
|
||||||
|
<group name="id">
|
||||||
|
<groupExpression><![CDATA[$F{id}]]></groupExpression>
|
||||||
|
</group>
|
||||||
|
<group name="title">
|
||||||
|
<groupExpression><![CDATA[$F{title}]]></groupExpression>
|
||||||
|
</group>
|
||||||
|
<group name="description">
|
||||||
|
<groupExpression><![CDATA[$F{description}]]></groupExpression>
|
||||||
|
</group>
|
||||||
|
<group name="relatedFindings">
|
||||||
|
<groupExpression><![CDATA[$F{attachments}]]></groupExpression>
|
||||||
|
</group>
|
||||||
|
<background>
|
||||||
|
<band splitType="Stretch"/>
|
||||||
|
</background>
|
||||||
|
<detail>
|
||||||
|
<band height="280" splitType="Stretch">
|
||||||
|
<staticText>
|
||||||
|
<reportElement x="0" y="50" width="100" height="19" forecolor="#232B44" uuid="27e653a4-f25c-4e14-a2dd-98639beaa958"/>
|
||||||
|
<textElement>
|
||||||
|
<font size="12" isBold="true"/>
|
||||||
|
</textElement>
|
||||||
|
<text><![CDATA[Title:]]></text>
|
||||||
|
</staticText>
|
||||||
|
<staticText>
|
||||||
|
<reportElement positionType="Float" x="0" y="120" width="100" height="20" forecolor="#232B44" uuid="4f0f0eaf-177b-4af7-99d8-a46b0faa9357"/>
|
||||||
|
<textElement>
|
||||||
|
<font size="12" isBold="true"/>
|
||||||
|
</textElement>
|
||||||
|
<text><![CDATA[Description:]]></text>
|
||||||
|
</staticText>
|
||||||
|
<textField textAdjust="StretchHeight">
|
||||||
|
<reportElement x="0" y="70" width="530" height="30" uuid="62ff1e8e-7987-4cd0-a79e-536859418d32"/>
|
||||||
|
<textElement>
|
||||||
|
<font size="12"/>
|
||||||
|
</textElement>
|
||||||
|
<textFieldExpression><![CDATA[$F{title}]]></textFieldExpression>
|
||||||
|
</textField>
|
||||||
|
<textField textAdjust="StretchHeight">
|
||||||
|
<reportElement positionType="Float" x="0" y="140" width="530" height="40" uuid="7e9aa6ea-d9f7-4879-bbca-753e3d654996"/>
|
||||||
|
<textElement>
|
||||||
|
<font size="12"/>
|
||||||
|
</textElement>
|
||||||
|
<textFieldExpression><![CDATA[$F{description}]]></textFieldExpression>
|
||||||
|
</textField>
|
||||||
|
<rectangle>
|
||||||
|
<reportElement x="0" y="-12" width="575" height="33" forecolor="#35A4FE" backcolor="#35A4FE" uuid="6b56d210-7a17-4ac9-bab8-b27008e039e4"/>
|
||||||
|
<graphicElement>
|
||||||
|
<pen lineWidth="0.0"/>
|
||||||
|
</graphicElement>
|
||||||
|
</rectangle>
|
||||||
|
<ellipse>
|
||||||
|
<reportElement x="-19" y="-12" width="40" height="33" forecolor="#35A4FE" backcolor="#35A4FE" uuid="fa27cf34-9e98-4d59-9cd2-9f436f0b6c25"/>
|
||||||
|
<graphicElement>
|
||||||
|
<pen lineWidth="0.0"/>
|
||||||
|
</graphicElement>
|
||||||
|
</ellipse>
|
||||||
|
<textField textAdjust="StretchHeight">
|
||||||
|
<reportElement x="80" y="-12" width="480" height="32" forecolor="#FFFFFF" uuid="f3b19575-bca9-450c-93bf-f9abbfe15bde"/>
|
||||||
|
<textElement verticalAlignment="Middle">
|
||||||
|
<font size="14" isBold="true"/>
|
||||||
|
</textElement>
|
||||||
|
<textFieldExpression><![CDATA[$F{id}]]></textFieldExpression>
|
||||||
|
</textField>
|
||||||
|
<staticText>
|
||||||
|
<reportElement x="0" y="-12" width="80" height="32" forecolor="#FFFFFF" uuid="06c9b872-ccec-44a6-854f-ef7b5dcedec9"/>
|
||||||
|
<textElement verticalAlignment="Middle">
|
||||||
|
<font size="14" isBold="true"/>
|
||||||
|
</textElement>
|
||||||
|
<text><![CDATA[Comment:]]></text>
|
||||||
|
</staticText>
|
||||||
|
</band>
|
||||||
|
</detail>
|
||||||
|
</jasperReport>
|
Binary file not shown.
|
@ -0,0 +1,213 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<!-- Created with Jaspersoft Studio version 6.20.0.final using JasperReports Library version 6.20.0-2bc7ab61c56f459e8176eb05c7705e145cd400ad -->
|
||||||
|
<jasperReport xmlns="http://jasperreports.sourceforge.net/jasperreports" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://jasperreports.sourceforge.net/jasperreports http://jasperreports.sourceforge.net/xsd/jasperreport.xsd" name="FindingsSubreport" pageWidth="595" pageHeight="842" columnWidth="555" leftMargin="20" rightMargin="20" topMargin="20" bottomMargin="20" uuid="e998075b-1539-4178-93ab-d58a24d7a1a1">
|
||||||
|
<property name="com.jaspersoft.studio.data.defaultdataadapter" value="ProjectReportJasperData Template JSON Adapter"/>
|
||||||
|
<style name="SeverityStyles">
|
||||||
|
<conditionalStyle>
|
||||||
|
<conditionExpression><![CDATA[$F{severity}.equals("LOW")]]></conditionExpression>
|
||||||
|
<style forecolor="#01D68F" backcolor="#01D68F"/>
|
||||||
|
</conditionalStyle>
|
||||||
|
<conditionalStyle>
|
||||||
|
<conditionExpression><![CDATA[$F{severity}.equals("MEDIUM")]]></conditionExpression>
|
||||||
|
<style forecolor="#35A4FE" backcolor="#35A4FE"/>
|
||||||
|
</conditionalStyle>
|
||||||
|
<conditionalStyle>
|
||||||
|
<conditionExpression><![CDATA[$F{severity}.equals("HIGH")]]></conditionExpression>
|
||||||
|
<style forecolor="#FFAB00" backcolor="#FFAB00"/>
|
||||||
|
</conditionalStyle>
|
||||||
|
<conditionalStyle>
|
||||||
|
<conditionExpression><![CDATA[$F{severity}.equals("CRITICAL")]]></conditionExpression>
|
||||||
|
<style forecolor="#FF3D70" backcolor="#FF3D70"/>
|
||||||
|
</conditionalStyle>
|
||||||
|
</style>
|
||||||
|
<style name="URL">
|
||||||
|
<conditionalStyle>
|
||||||
|
<conditionExpression><![CDATA[$F{affectedUrls}.size() > 0]]></conditionExpression>
|
||||||
|
<style forecolor="#3267FE" backcolor="#3267FE" isUnderline="true"/>
|
||||||
|
</conditionalStyle>
|
||||||
|
</style>
|
||||||
|
<subDataset name="AffectedUrlsList" uuid="847d946c-60fb-4c27-bfef-875d197d89f9">
|
||||||
|
<queryString>
|
||||||
|
<![CDATA[]]>
|
||||||
|
</queryString>
|
||||||
|
<field name="_THIS" class="java.lang.String"/>
|
||||||
|
</subDataset>
|
||||||
|
<queryString language="json">
|
||||||
|
<![CDATA[projectReportData.projectPentestReport.findings]]>
|
||||||
|
</queryString>
|
||||||
|
<field name="id" class="java.lang.String">
|
||||||
|
<property name="net.sf.jasperreports.json.field.expression" value="id"/>
|
||||||
|
<fieldDescription><![CDATA[id]]></fieldDescription>
|
||||||
|
</field>
|
||||||
|
<field name="severity" class="java.lang.String">
|
||||||
|
<property name="net.sf.jasperreports.json.field.expression" value="severity"/>
|
||||||
|
<fieldDescription><![CDATA[severity]]></fieldDescription>
|
||||||
|
</field>
|
||||||
|
<field name="title" class="java.lang.String">
|
||||||
|
<property name="net.sf.jasperreports.json.field.expression" value="title"/>
|
||||||
|
<fieldDescription><![CDATA[title]]></fieldDescription>
|
||||||
|
</field>
|
||||||
|
<field name="description" class="java.lang.String">
|
||||||
|
<property name="net.sf.jasperreports.json.field.expression" value="description"/>
|
||||||
|
<fieldDescription><![CDATA[description]]></fieldDescription>
|
||||||
|
</field>
|
||||||
|
<field name="impact" class="java.lang.String">
|
||||||
|
<property name="net.sf.jasperreports.json.field.expression" value="impact"/>
|
||||||
|
<fieldDescription><![CDATA[impact]]></fieldDescription>
|
||||||
|
</field>
|
||||||
|
<field name="affectedUrls" class="java.util.ArrayList">
|
||||||
|
<property name="net.sf.jasperreports.json.field.expression" value="affectedUrls"/>
|
||||||
|
<fieldDescription><![CDATA[affectedUrls]]></fieldDescription>
|
||||||
|
</field>
|
||||||
|
<field name="reproduction" class="java.lang.String">
|
||||||
|
<property name="net.sf.jasperreports.json.field.expression" value="reproduction"/>
|
||||||
|
<fieldDescription><![CDATA[reproduction]]></fieldDescription>
|
||||||
|
</field>
|
||||||
|
<field name="mitigation" class="java.lang.String">
|
||||||
|
<property name="net.sf.jasperreports.json.field.expression" value="mitigation"/>
|
||||||
|
<fieldDescription><![CDATA[mitigation]]></fieldDescription>
|
||||||
|
</field>
|
||||||
|
<field name="attachments" class="java.util.ArrayList"/>
|
||||||
|
<background>
|
||||||
|
<band splitType="Stretch"/>
|
||||||
|
</background>
|
||||||
|
<detail>
|
||||||
|
<band height="600" splitType="Stretch">
|
||||||
|
<ellipse>
|
||||||
|
<reportElement key="" style="SeverityStyles" mode="Opaque" x="445" y="45" width="30" height="30" uuid="5dfe3093-6943-446e-8126-d7230d895b0c"/>
|
||||||
|
<graphicElement>
|
||||||
|
<pen lineWidth="0.0"/>
|
||||||
|
</graphicElement>
|
||||||
|
</ellipse>
|
||||||
|
<textField textAdjust="StretchHeight">
|
||||||
|
<reportElement positionType="Float" x="0" y="140" width="530" height="40" uuid="2882cfe1-475e-4ac3-a987-38cb01a462f4"/>
|
||||||
|
<textElement>
|
||||||
|
<font size="12"/>
|
||||||
|
</textElement>
|
||||||
|
<textFieldExpression><![CDATA[$F{description}]]></textFieldExpression>
|
||||||
|
</textField>
|
||||||
|
<staticText>
|
||||||
|
<reportElement positionType="Float" x="0" y="120" width="100" height="20" forecolor="#232B44" uuid="cb620215-7d9a-422e-a286-d1374c29469a"/>
|
||||||
|
<textElement>
|
||||||
|
<font size="12" isBold="true"/>
|
||||||
|
</textElement>
|
||||||
|
<text><![CDATA[Description:]]></text>
|
||||||
|
</staticText>
|
||||||
|
<staticText>
|
||||||
|
<reportElement x="0" y="50" width="100" height="20" forecolor="#232B44" uuid="a8c19344-4ce8-4d15-919b-4cbb004aba79"/>
|
||||||
|
<textElement>
|
||||||
|
<font size="12" isBold="true"/>
|
||||||
|
</textElement>
|
||||||
|
<text><![CDATA[Title:]]></text>
|
||||||
|
</staticText>
|
||||||
|
<textField textAdjust="StretchHeight">
|
||||||
|
<reportElement x="0" y="70" width="430" height="30" uuid="1ac22e9e-2fe9-4fc7-94ca-5e30db7aa74f"/>
|
||||||
|
<textElement>
|
||||||
|
<font size="12"/>
|
||||||
|
</textElement>
|
||||||
|
<textFieldExpression><![CDATA[$F{title}]]></textFieldExpression>
|
||||||
|
</textField>
|
||||||
|
<staticText>
|
||||||
|
<reportElement positionType="Float" x="0" y="200" width="100" height="20" forecolor="#232B44" uuid="3d056116-a999-4c17-b3b0-94b26e69c9c6"/>
|
||||||
|
<textElement>
|
||||||
|
<font size="12" isBold="true"/>
|
||||||
|
</textElement>
|
||||||
|
<text><![CDATA[Impact:]]></text>
|
||||||
|
</staticText>
|
||||||
|
<textField textAdjust="StretchHeight">
|
||||||
|
<reportElement positionType="Float" x="0" y="220" width="530" height="40" uuid="d026c3e2-1431-4010-b0d7-bf07cb339ed7"/>
|
||||||
|
<textElement>
|
||||||
|
<font size="12"/>
|
||||||
|
</textElement>
|
||||||
|
<textFieldExpression><![CDATA[$F{impact}]]></textFieldExpression>
|
||||||
|
</textField>
|
||||||
|
<textField textAdjust="StretchHeight">
|
||||||
|
<reportElement positionType="Float" x="0" y="300" width="530" height="40" uuid="8d1f42e3-a821-475e-b862-126018ae2e95"/>
|
||||||
|
<textElement>
|
||||||
|
<font size="12"/>
|
||||||
|
</textElement>
|
||||||
|
<textFieldExpression><![CDATA[$F{reproduction}]]></textFieldExpression>
|
||||||
|
</textField>
|
||||||
|
<staticText>
|
||||||
|
<reportElement positionType="Float" x="0" y="280" width="180" height="20" forecolor="#232B44" uuid="5d0ab6e7-dd18-4da2-848b-95abc47936e8"/>
|
||||||
|
<textElement>
|
||||||
|
<font size="12" isBold="true"/>
|
||||||
|
</textElement>
|
||||||
|
<text><![CDATA[Reproduction Steps:]]></text>
|
||||||
|
</staticText>
|
||||||
|
<textField textAdjust="StretchHeight">
|
||||||
|
<reportElement positionType="Float" x="0" y="380" width="530" height="40" uuid="09dea210-c47a-486e-b461-c6fb7c27bb39"/>
|
||||||
|
<textElement>
|
||||||
|
<font size="12"/>
|
||||||
|
</textElement>
|
||||||
|
<textFieldExpression><![CDATA[(($F{mitigation}.length() == 0) ? "No mitigation to avoid, minimize or compensate the finding found or needed." : $F{mitigation})]]></textFieldExpression>
|
||||||
|
</textField>
|
||||||
|
<staticText>
|
||||||
|
<reportElement positionType="Float" x="0" y="360" width="180" height="20" forecolor="#232B44" uuid="0aaec1e4-9ac0-48de-96ef-0ac5ad1e9be0"/>
|
||||||
|
<textElement>
|
||||||
|
<font size="12" isBold="true"/>
|
||||||
|
</textElement>
|
||||||
|
<text><![CDATA[Mitigation:]]></text>
|
||||||
|
</staticText>
|
||||||
|
<rectangle>
|
||||||
|
<reportElement x="0" y="-12" width="575" height="33" forecolor="#FF3D70" backcolor="#FF3D70" uuid="cb580eb9-9492-4fb6-8eb7-304e50612c9f"/>
|
||||||
|
<graphicElement>
|
||||||
|
<pen lineWidth="0.0"/>
|
||||||
|
</graphicElement>
|
||||||
|
</rectangle>
|
||||||
|
<ellipse>
|
||||||
|
<reportElement x="-19" y="-12" width="40" height="33" forecolor="#FF3D70" backcolor="#FF3D70" uuid="b7284920-9281-446c-a04f-0e5c1b433cd5"/>
|
||||||
|
<graphicElement>
|
||||||
|
<pen lineWidth="0.0"/>
|
||||||
|
</graphicElement>
|
||||||
|
</ellipse>
|
||||||
|
<textField textAdjust="StretchHeight">
|
||||||
|
<reportElement x="80" y="-12" width="480" height="32" forecolor="#FFFFFF" uuid="fd9a8e55-90df-468c-920e-f4154c0c0476"/>
|
||||||
|
<textElement verticalAlignment="Middle">
|
||||||
|
<font size="14" isBold="true"/>
|
||||||
|
</textElement>
|
||||||
|
<textFieldExpression><![CDATA[$F{id}]]></textFieldExpression>
|
||||||
|
</textField>
|
||||||
|
<rectangle>
|
||||||
|
<reportElement style="SeverityStyles" mode="Opaque" x="460" y="45" width="70" height="30" uuid="6b40b4f8-4f4a-4e2e-9eb8-dcb32646353d"/>
|
||||||
|
<graphicElement>
|
||||||
|
<pen lineWidth="0.0"/>
|
||||||
|
</graphicElement>
|
||||||
|
</rectangle>
|
||||||
|
<ellipse>
|
||||||
|
<reportElement style="SeverityStyles" mode="Opaque" x="515" y="45" width="30" height="30" uuid="a9c34649-525e-40e7-b9c6-4132773009d3"/>
|
||||||
|
<graphicElement>
|
||||||
|
<pen lineWidth="0.0"/>
|
||||||
|
</graphicElement>
|
||||||
|
</ellipse>
|
||||||
|
<textField textAdjust="StretchHeight">
|
||||||
|
<reportElement x="460" y="50" width="70" height="20" forecolor="#FEFEFF" uuid="c2c6ef50-1470-41aa-80a1-44db4bbc1b64"/>
|
||||||
|
<textElement textAlignment="Center" verticalAlignment="Middle">
|
||||||
|
<font size="12"/>
|
||||||
|
</textElement>
|
||||||
|
<textFieldExpression><![CDATA[$F{severity}]]></textFieldExpression>
|
||||||
|
</textField>
|
||||||
|
<textField textAdjust="StretchHeight">
|
||||||
|
<reportElement style="URL" positionType="Float" x="0" y="460" width="530" height="40" uuid="9d6be22b-6f8c-41bf-ab85-3d5901979a06"/>
|
||||||
|
<textElement>
|
||||||
|
<font size="12"/>
|
||||||
|
</textElement>
|
||||||
|
<textFieldExpression><![CDATA[(($F{affectedUrls}.size() == 0) ? "No specific URL's affected." : $F{affectedUrls}.toString().substring(1, $F{affectedUrls}.toString().length() - 1))]]></textFieldExpression>
|
||||||
|
</textField>
|
||||||
|
<staticText>
|
||||||
|
<reportElement positionType="Float" x="0" y="440" width="180" height="20" forecolor="#232B44" uuid="003646c0-fc53-4add-84d2-b3816d52789d"/>
|
||||||
|
<textElement>
|
||||||
|
<font size="12" isBold="true"/>
|
||||||
|
</textElement>
|
||||||
|
<text><![CDATA[Affected URL's:]]></text>
|
||||||
|
</staticText>
|
||||||
|
<staticText>
|
||||||
|
<reportElement x="0" y="-12" width="80" height="32" forecolor="#FFFFFF" uuid="c6ec29f3-3687-4098-80b5-30fd33a7989a"/>
|
||||||
|
<textElement verticalAlignment="Middle">
|
||||||
|
<font size="14" isBold="true"/>
|
||||||
|
</textElement>
|
||||||
|
<text><![CDATA[Finding:]]></text>
|
||||||
|
</staticText>
|
||||||
|
</band>
|
||||||
|
</detail>
|
||||||
|
</jasperReport>
|
|
@ -0,0 +1,190 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<!-- Created with Jaspersoft Studio version 6.20.0.final using JasperReports Library version 6.20.0-2bc7ab61c56f459e8176eb05c7705e145cd400ad -->
|
||||||
|
<jasperReport xmlns="http://jasperreports.sourceforge.net/jasperreports" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://jasperreports.sourceforge.net/jasperreports http://jasperreports.sourceforge.net/xsd/jasperreport.xsd" name="SeverityRatingTableSubreport" pageWidth="595" pageHeight="842" columnWidth="555" leftMargin="20" rightMargin="20" topMargin="20" bottomMargin="20" uuid="6a3399a9-b8f7-4c58-a21d-8578e392dc84">
|
||||||
|
<style name="Table_TH" mode="Opaque" backcolor="#232B44">
|
||||||
|
<box>
|
||||||
|
<pen lineWidth="0.5" lineColor="#232B44"/>
|
||||||
|
<topPen lineWidth="0.5" lineColor="#232B44"/>
|
||||||
|
<leftPen lineWidth="0.5" lineColor="#232B44"/>
|
||||||
|
<bottomPen lineWidth="0.5" lineColor="#232B44"/>
|
||||||
|
<rightPen lineWidth="0.5" lineColor="#232B44"/>
|
||||||
|
</box>
|
||||||
|
</style>
|
||||||
|
<style name="Table_CH" mode="Opaque" backcolor="#FEFEFF">
|
||||||
|
<box>
|
||||||
|
<pen lineWidth="0.5" lineColor="#232B44"/>
|
||||||
|
<topPen lineWidth="0.5" lineColor="#232B44"/>
|
||||||
|
<leftPen lineWidth="0.5" lineColor="#232B44"/>
|
||||||
|
<bottomPen lineWidth="0.5" lineColor="#232B44"/>
|
||||||
|
<rightPen lineWidth="0.5" lineColor="#232B44"/>
|
||||||
|
</box>
|
||||||
|
</style>
|
||||||
|
<style name="Table_TD" mode="Opaque" backcolor="#FFFFFF">
|
||||||
|
<box>
|
||||||
|
<pen lineWidth="0.5" lineColor="#232B44"/>
|
||||||
|
<topPen lineWidth="0.5" lineColor="#232B44"/>
|
||||||
|
<leftPen lineWidth="0.5" lineColor="#232B44"/>
|
||||||
|
<bottomPen lineWidth="0.5" lineColor="#232B44"/>
|
||||||
|
<rightPen lineWidth="0.5" lineColor="#232B44"/>
|
||||||
|
</box>
|
||||||
|
</style>
|
||||||
|
<subDataset name="SeverityRatingDefinition" uuid="adea3afd-3a9c-4386-b540-562fde7a2419">
|
||||||
|
<queryString>
|
||||||
|
<![CDATA[]]>
|
||||||
|
</queryString>
|
||||||
|
</subDataset>
|
||||||
|
<queryString>
|
||||||
|
<![CDATA[]]>
|
||||||
|
</queryString>
|
||||||
|
<background>
|
||||||
|
<band splitType="Stretch"/>
|
||||||
|
</background>
|
||||||
|
<detail>
|
||||||
|
<band height="620" splitType="Stretch">
|
||||||
|
<componentElement>
|
||||||
|
<reportElement positionType="Float" x="-20" y="-20" width="560" height="620" uuid="10d88177-713d-4c60-9266-5afb31684f19">
|
||||||
|
<property name="com.jaspersoft.studio.layout" value="com.jaspersoft.studio.editor.layout.VerticalRowLayout"/>
|
||||||
|
<property name="com.jaspersoft.studio.table.style.table_header" value="Table_TH"/>
|
||||||
|
<property name="com.jaspersoft.studio.table.style.column_header" value="Table_CH"/>
|
||||||
|
<property name="com.jaspersoft.studio.table.style.detail" value="Table_TD"/>
|
||||||
|
<property name="com.jaspersoft.studio.components.autoresize.proportional" value="true"/>
|
||||||
|
</reportElement>
|
||||||
|
<jr:table xmlns:jr="http://jasperreports.sourceforge.net/jasperreports/components" xsi:schemaLocation="http://jasperreports.sourceforge.net/jasperreports/components http://jasperreports.sourceforge.net/xsd/components.xsd" whenNoDataType="AllSectionsNoDetail">
|
||||||
|
<datasetRun subDataset="SeverityRatingDefinition" uuid="297fe663-872d-43d4-a947-9106a126a556">
|
||||||
|
<dataSourceExpression><![CDATA[new net.sf.jasperreports.engine.JREmptyDataSource()]]></dataSourceExpression>
|
||||||
|
</datasetRun>
|
||||||
|
<jr:column width="112" uuid="dd4a463a-7807-42ae-9419-7a17135a2a58">
|
||||||
|
<property name="com.jaspersoft.studio.components.table.model.column.name" value="Column1"/>
|
||||||
|
<jr:tableHeader style="Table_TH" height="30" rowSpan="1">
|
||||||
|
<staticText>
|
||||||
|
<reportElement x="0" y="0" width="112" height="30" forecolor="#FFFFFF" uuid="140fe665-f028-4805-a55f-4b4190be3140"/>
|
||||||
|
<textElement textAlignment="Center" verticalAlignment="Middle">
|
||||||
|
<font size="12" isBold="true"/>
|
||||||
|
</textElement>
|
||||||
|
<text><![CDATA[Rating]]></text>
|
||||||
|
</staticText>
|
||||||
|
</jr:tableHeader>
|
||||||
|
<jr:tableFooter style="Table_CH" height="200" rowSpan="1">
|
||||||
|
<staticText>
|
||||||
|
<reportElement positionType="Float" stretchType="ContainerHeight" x="0" y="0" width="112" height="200" forecolor="#03C886" uuid="bb091668-8003-45fc-a4aa-e54a96f7fa87"/>
|
||||||
|
<textElement textAlignment="Center" verticalAlignment="Middle">
|
||||||
|
<font size="16" isBold="true"/>
|
||||||
|
</textElement>
|
||||||
|
<text><![CDATA[Low]]></text>
|
||||||
|
</staticText>
|
||||||
|
</jr:tableFooter>
|
||||||
|
<jr:columnHeader style="Table_CH" height="90" rowSpan="1">
|
||||||
|
<staticText>
|
||||||
|
<reportElement positionType="Float" stretchType="ContainerHeight" x="0" y="0" width="112" height="90" forecolor="#FF3D70" uuid="d742063f-e537-400f-bb31-bb55fa9f20fd"/>
|
||||||
|
<textElement textAlignment="Center" verticalAlignment="Middle">
|
||||||
|
<font size="16" isBold="true"/>
|
||||||
|
</textElement>
|
||||||
|
<text><![CDATA[Critical]]></text>
|
||||||
|
</staticText>
|
||||||
|
</jr:columnHeader>
|
||||||
|
<jr:columnFooter style="Table_CH" height="200" rowSpan="1">
|
||||||
|
<staticText>
|
||||||
|
<reportElement positionType="Float" stretchType="ContainerHeight" x="0" y="0" width="112" height="200" forecolor="#35A4FE" uuid="a8b12a40-8144-4226-870f-0e0a1e5ea752"/>
|
||||||
|
<textElement textAlignment="Center" verticalAlignment="Middle">
|
||||||
|
<font size="16" isBold="true"/>
|
||||||
|
</textElement>
|
||||||
|
<text><![CDATA[Medium]]></text>
|
||||||
|
</staticText>
|
||||||
|
</jr:columnFooter>
|
||||||
|
<jr:detailCell style="Table_TD" height="100">
|
||||||
|
<staticText>
|
||||||
|
<reportElement positionType="Float" stretchType="ContainerHeight" x="0" y="0" width="112" height="100" forecolor="#FFAB00" uuid="4a1dd484-384f-45ca-a41a-8d1d2b5fb1e6"/>
|
||||||
|
<textElement textAlignment="Center" verticalAlignment="Middle">
|
||||||
|
<font size="16" isBold="true"/>
|
||||||
|
</textElement>
|
||||||
|
<text><![CDATA[High]]></text>
|
||||||
|
</staticText>
|
||||||
|
</jr:detailCell>
|
||||||
|
</jr:column>
|
||||||
|
<jr:column width="448" uuid="ab851b91-c506-48d4-a4e6-77292e4c42ef">
|
||||||
|
<property name="com.jaspersoft.studio.components.table.model.column.name" value="Column2"/>
|
||||||
|
<jr:tableHeader style="Table_TH" height="30" rowSpan="1">
|
||||||
|
<staticText>
|
||||||
|
<reportElement x="0" y="0" width="448" height="30" forecolor="#FFFFFF" uuid="7c3f036d-ed06-4aa2-bba2-f45c7eb91316">
|
||||||
|
<property name="com.jaspersoft.studio.unit.leftIndent" value="px"/>
|
||||||
|
</reportElement>
|
||||||
|
<textElement textAlignment="Left" verticalAlignment="Middle">
|
||||||
|
<font size="12" isBold="true"/>
|
||||||
|
<paragraph leftIndent="2"/>
|
||||||
|
</textElement>
|
||||||
|
<text><![CDATA[Severity Rating Definition]]></text>
|
||||||
|
</staticText>
|
||||||
|
</jr:tableHeader>
|
||||||
|
<jr:tableFooter style="Table_CH" height="200" rowSpan="1">
|
||||||
|
<staticText>
|
||||||
|
<reportElement positionType="Float" stretchType="ContainerHeight" x="0" y="0" width="448" height="200" uuid="9e066b11-0381-46ce-a05b-99b2293ce66c">
|
||||||
|
<property name="com.jaspersoft.studio.unit.leftIndent" value="px"/>
|
||||||
|
</reportElement>
|
||||||
|
<textElement>
|
||||||
|
<font size="12"/>
|
||||||
|
<paragraph leftIndent="2"/>
|
||||||
|
</textElement>
|
||||||
|
<text><![CDATA[Exploitation of the technical or procedural vulnerability will cause minimal impact to operations. The
|
||||||
|
Confidentiality, Integrity and Availability (CIA) of sensitive information are not at risk of compromise.
|
||||||
|
Exploitation of the vulnerability may cause slight financial loss or public embarrassment. The threat exposure is
|
||||||
|
moderate-to-low. Security controls are in place to contain the severity of impact if the vulnerability were
|
||||||
|
exploited, such that further political, financial, or legal damage will not occur.
|
||||||
|
- OR -
|
||||||
|
The vulnerability is such that it would otherwise be considered Medium Risk, but the threat exposure is so limited
|
||||||
|
that the likelihood of occurrence is minimal.]]></text>
|
||||||
|
</staticText>
|
||||||
|
</jr:tableFooter>
|
||||||
|
<jr:columnHeader style="Table_CH" height="90" rowSpan="1">
|
||||||
|
<staticText>
|
||||||
|
<reportElement positionType="Float" stretchType="ContainerHeight" x="0" y="0" width="448" height="90" uuid="628591b9-4f90-45cf-896c-e38355ed9de8">
|
||||||
|
<property name="com.jaspersoft.studio.unit.firstLineIndent" value="pixel"/>
|
||||||
|
<property name="com.jaspersoft.studio.unit.leftIndent" value="px"/>
|
||||||
|
</reportElement>
|
||||||
|
<textElement textAlignment="Left">
|
||||||
|
<font size="12"/>
|
||||||
|
<paragraph lineSpacingSize="1.0" leftIndent="2"/>
|
||||||
|
</textElement>
|
||||||
|
<text><![CDATA[Exploitation of the technical or procedural vulnerability will cause substantial harm. Significant political,
|
||||||
|
financial, and/or legal damage is likely to result. The threat exposure is critical, and a publicly available mechanism exists to exploit the vulnerability. Security controls are not effectively implemented to reduce the severity of impact if the vulnerability were exploited.]]></text>
|
||||||
|
</staticText>
|
||||||
|
</jr:columnHeader>
|
||||||
|
<jr:columnFooter style="Table_CH" height="200" rowSpan="1">
|
||||||
|
<staticText>
|
||||||
|
<reportElement positionType="Float" stretchType="ContainerHeight" x="0" y="0" width="448" height="200" uuid="b9e7a6f9-946f-4824-8a9e-24bc3279589a">
|
||||||
|
<property name="com.jaspersoft.studio.unit.leftIndent" value="px"/>
|
||||||
|
</reportElement>
|
||||||
|
<textElement>
|
||||||
|
<font size="12"/>
|
||||||
|
<paragraph leftIndent="2"/>
|
||||||
|
</textElement>
|
||||||
|
<text><![CDATA[Exploitation of the technical or procedural vulnerability will significantly impact the confidentiality, integrity,
|
||||||
|
and/or availability of the system, application, or data. Exploitation of the vulnerability may cause moderate
|
||||||
|
financial loss or public embarrassment. The threat exposure is moderate-to-high, thereby increasing the
|
||||||
|
likelihood of occurrence. Security controls are in place to contain the severity of impact if the vulnerability were
|
||||||
|
exploited, such that further political, financial, or legal damage will not occur.
|
||||||
|
- OR -
|
||||||
|
The vulnerability is such that it would otherwise be considered High Risk, but the threat exposure is so limited
|
||||||
|
that the likelihood of occurrence is minimal.]]></text>
|
||||||
|
</staticText>
|
||||||
|
</jr:columnFooter>
|
||||||
|
<jr:detailCell style="Table_TD" height="100">
|
||||||
|
<staticText>
|
||||||
|
<reportElement positionType="Float" stretchType="ContainerHeight" x="0" y="0" width="448" height="100" uuid="8a292592-81b2-49a1-bfda-e9540ecb3aa9">
|
||||||
|
<property name="com.jaspersoft.studio.unit.leftIndent" value="px"/>
|
||||||
|
</reportElement>
|
||||||
|
<textElement>
|
||||||
|
<font size="12"/>
|
||||||
|
<paragraph leftIndent="2"/>
|
||||||
|
</textElement>
|
||||||
|
<text><![CDATA[Exploitation of the technical or procedural vulnerability will cause substantial harm. Significant political,
|
||||||
|
financial, and/or legal damage is likely to result. The threat exposure is high, thereby increasing the likelihood of
|
||||||
|
occurrence. Security controls are not effectively implemented to reduce the severity of impact if the vulnerability
|
||||||
|
were exploited.]]></text>
|
||||||
|
</staticText>
|
||||||
|
</jr:detailCell>
|
||||||
|
</jr:column>
|
||||||
|
</jr:table>
|
||||||
|
</componentElement>
|
||||||
|
</band>
|
||||||
|
</detail>
|
||||||
|
</jasperReport>
|
|
@ -14,7 +14,8 @@
|
||||||
"https://akveo.github.io/nebular/docs/components/progress-bar/examples#nbprogressbarcomponent"
|
"https://akveo.github.io/nebular/docs/components/progress-bar/examples#nbprogressbarcomponent"
|
||||||
],
|
],
|
||||||
"reproduction": "Step 1: Test",
|
"reproduction": "Step 1: Test",
|
||||||
"mitigation": "Test Mitigation"
|
"mitigation": "Test Mitigation",
|
||||||
|
"attachments": []
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id": "58f63b4e-97fb-4fe8-8527-7996896089d2",
|
"id": "58f63b4e-97fb-4fe8-8527-7996896089d2",
|
||||||
|
@ -24,7 +25,8 @@
|
||||||
"impact": "Medium",
|
"impact": "Medium",
|
||||||
"affectedUrls": [],
|
"affectedUrls": [],
|
||||||
"reproduction": "Medium",
|
"reproduction": "Medium",
|
||||||
"mitigation": ""
|
"mitigation": "",
|
||||||
|
"attachments": []
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"comments": [
|
"comments": [
|
||||||
|
@ -32,7 +34,7 @@
|
||||||
"id": "89703b19-16c7-49e5-8e33-0c706313e5fe",
|
"id": "89703b19-16c7-49e5-8e33-0c706313e5fe",
|
||||||
"title": "Test Comment",
|
"title": "Test Comment",
|
||||||
"description": "No related findings",
|
"description": "No related findings",
|
||||||
"relatedFindings": []
|
"attachments": []
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"status": "COMPLETED"
|
"status": "COMPLETED"
|
||||||
|
@ -50,7 +52,8 @@
|
||||||
"impact": "High",
|
"impact": "High",
|
||||||
"affectedUrls": [],
|
"affectedUrls": [],
|
||||||
"reproduction": "High",
|
"reproduction": "High",
|
||||||
"mitigation": ""
|
"mitigation": "",
|
||||||
|
"attachments": []
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"comments": [],
|
"comments": [],
|
||||||
|
|
|
@ -22,7 +22,8 @@
|
||||||
"https://www.google.de/"
|
"https://www.google.de/"
|
||||||
],
|
],
|
||||||
"reproduction": "Step 1: Test",
|
"reproduction": "Step 1: Test",
|
||||||
"mitigation": ""
|
"mitigation": "",
|
||||||
|
"attachments": []
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id": "58f63b4e-97fb-4fe8-8527-7996896089d2",
|
"id": "58f63b4e-97fb-4fe8-8527-7996896089d2",
|
||||||
|
@ -32,7 +33,8 @@
|
||||||
"impact": "Medium Impact",
|
"impact": "Medium Impact",
|
||||||
"affectedUrls": [],
|
"affectedUrls": [],
|
||||||
"reproduction": "Step 1: Medium",
|
"reproduction": "Step 1: Medium",
|
||||||
"mitigation": "Fusce sit amet massa efficitur, egestas neque vitae, elementum orci. Nullam accumsan nunc id risus volutpat, quis sagittis lorem sollicitudin. Nam finibus justo non arcu vulputate dignissim. Etiam libero felis, dignissim non feugiat at, ornare non elit. Sed hendrerit risus id magna porttitor interdum."
|
"mitigation": "Fusce sit amet massa efficitur, egestas neque vitae, elementum orci. Nullam accumsan nunc id risus volutpat, quis sagittis lorem sollicitudin. Nam finibus justo non arcu vulputate dignissim. Etiam libero felis, dignissim non feugiat at, ornare non elit. Sed hendrerit risus id magna porttitor interdum.",
|
||||||
|
"attachments": []
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id": "58f63b4e-97fb-4fe8-8527-7996896089d2",
|
"id": "58f63b4e-97fb-4fe8-8527-7996896089d2",
|
||||||
|
@ -42,7 +44,8 @@
|
||||||
"impact": "High Impact",
|
"impact": "High Impact",
|
||||||
"affectedUrls": [],
|
"affectedUrls": [],
|
||||||
"reproduction": "Step 1: High",
|
"reproduction": "Step 1: High",
|
||||||
"mitigation": ""
|
"mitigation": "",
|
||||||
|
"attachments": []
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id": "58f63b4e-97fb-4fe8-8527-7996896089d2",
|
"id": "58f63b4e-97fb-4fe8-8527-7996896089d2",
|
||||||
|
@ -54,7 +57,8 @@
|
||||||
"https://community.jaspersoft.com/system/files/restricted-docs/jaspersoft-studio-user-guide.pdf"
|
"https://community.jaspersoft.com/system/files/restricted-docs/jaspersoft-studio-user-guide.pdf"
|
||||||
],
|
],
|
||||||
"reproduction": "Step 1: Critical",
|
"reproduction": "Step 1: Critical",
|
||||||
"mitigation": "Fusce sit amet massa efficitur, egestas neque vitae, elementum orci. Nullam accumsan nunc id risus volutpat, quis sagittis lorem sollicitudin. Nam finibus justo non arcu vulputate dignissim. Etiam libero felis, dignissim non feugiat at, ornare non elit. Sed hendrerit risus id magna porttitor interdum."
|
"mitigation": "Fusce sit amet massa efficitur, egestas neque vitae, elementum orci. Nullam accumsan nunc id risus volutpat, quis sagittis lorem sollicitudin. Nam finibus justo non arcu vulputate dignissim. Etiam libero felis, dignissim non feugiat at, ornare non elit. Sed hendrerit risus id magna porttitor interdum.",
|
||||||
|
"attachments": []
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"comments": [
|
"comments": [
|
||||||
|
@ -62,15 +66,13 @@
|
||||||
"id": "89703b19-16c7-49e5-8e33-0c706313e5fe",
|
"id": "89703b19-16c7-49e5-8e33-0c706313e5fe",
|
||||||
"title": "Test Comment",
|
"title": "Test Comment",
|
||||||
"description": "Not related to findings",
|
"description": "Not related to findings",
|
||||||
"relatedFindings": [
|
"attachments": []
|
||||||
"58f63b4e-97fb-4fe8-8527-7996896089d2"
|
|
||||||
]
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id": "89703b19-16c7-49e5-8e33-0c706313e5fe",
|
"id": "89703b19-16c7-49e5-8e33-0c706313e5fe",
|
||||||
"title": "Test Comment",
|
"title": "Test Comment",
|
||||||
"description": "Test Decription",
|
"description": "Test Decription",
|
||||||
"relatedFindings": []
|
"attachments": []
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"status": "COMPLETED"
|
"status": "COMPLETED"
|
||||||
|
@ -88,7 +90,8 @@
|
||||||
"impact": "High",
|
"impact": "High",
|
||||||
"affectedUrls": [],
|
"affectedUrls": [],
|
||||||
"reproduction": "High",
|
"reproduction": "High",
|
||||||
"mitigation": ""
|
"mitigation": "",
|
||||||
|
"attachments": []
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"comments": [],
|
"comments": [],
|
||||||
|
|
|
@ -23,7 +23,8 @@
|
||||||
"https://akveo.github.io/nebular/docs/components/progress-bar/examples#nbprogressbarcomponent"
|
"https://akveo.github.io/nebular/docs/components/progress-bar/examples#nbprogressbarcomponent"
|
||||||
],
|
],
|
||||||
"reproduction": "Step 1: Test",
|
"reproduction": "Step 1: Test",
|
||||||
"mitigation": "Test Mitigation"
|
"mitigation": "Test Mitigation",
|
||||||
|
"attachments": []
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id": "58f63b4e-97fb-4fe8-8527-7996896089d2",
|
"id": "58f63b4e-97fb-4fe8-8527-7996896089d2",
|
||||||
|
@ -33,7 +34,8 @@
|
||||||
"impact": "Medium",
|
"impact": "Medium",
|
||||||
"affectedUrls": [],
|
"affectedUrls": [],
|
||||||
"reproduction": "Medium",
|
"reproduction": "Medium",
|
||||||
"mitigation": ""
|
"mitigation": "",
|
||||||
|
"attachments": []
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"comments": [
|
"comments": [
|
||||||
|
@ -41,7 +43,7 @@
|
||||||
"id": "89703b19-16c7-49e5-8e33-0c706313e5fe",
|
"id": "89703b19-16c7-49e5-8e33-0c706313e5fe",
|
||||||
"title": "Test Comment",
|
"title": "Test Comment",
|
||||||
"description": "No related findings",
|
"description": "No related findings",
|
||||||
"relatedFindings": []
|
"attachments": []
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"status": "COMPLETED"
|
"status": "COMPLETED"
|
||||||
|
@ -59,7 +61,8 @@
|
||||||
"impact": "High",
|
"impact": "High",
|
||||||
"affectedUrls": [],
|
"affectedUrls": [],
|
||||||
"reproduction": "High",
|
"reproduction": "High",
|
||||||
"mitigation": ""
|
"mitigation": "",
|
||||||
|
"attachments": []
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"comments": [],
|
"comments": [],
|
||||||
|
|
Binary file not shown.
Before Width: | Height: | Size: 220 KiB After Width: | Height: | Size: 224 KiB |
File diff suppressed because one or more lines are too long
Loading…
Reference in New Issue