diff --git a/security-c4po-angular/src/app/objective-overview/objective-table/objective-table.component.html b/security-c4po-angular/src/app/objective-overview/objective-table/objective-table.component.html index 6ec2faa..e2a283f 100644 --- a/security-c4po-angular/src/app/objective-overview/objective-table/objective-table.component.html +++ b/security-c4po-angular/src/app/objective-overview/objective-table/objective-table.component.html @@ -1,5 +1,5 @@
- +
@@ -20,7 +25,12 @@ {{ 'comment.description' | translate }} diff --git a/security-c4po-angular/src/app/pentest/pentest-content/pentest-comments/pentest-comments.component.scss b/security-c4po-angular/src/app/pentest/pentest-content/pentest-comments/pentest-comments.component.scss index 3529cb2..8fe5db6 100644 --- a/security-c4po-angular/src/app/pentest/pentest-content/pentest-comments/pentest-comments.component.scss +++ b/security-c4po-angular/src/app/pentest/pentest-content/pentest-comments/pentest-comments.component.scss @@ -1,4 +1,5 @@ @import '../../../../assets/@theme/styles/themes'; +@import '../../../../assets/@theme/styles/_text-overflow.scss'; .comment-table { margin-right: 2rem; diff --git a/security-c4po-angular/src/app/pentest/pentest-content/pentest-findings/pentest-findings.component.html b/security-c4po-angular/src/app/pentest/pentest-content/pentest-findings/pentest-findings.component.html index e221a97..b3d44d3 100644 --- a/security-c4po-angular/src/app/pentest/pentest-content/pentest-findings/pentest-findings.component.html +++ b/security-c4po-angular/src/app/pentest/pentest-content/pentest-findings/pentest-findings.component.html @@ -11,7 +11,12 @@ {{ 'finding.title' | translate }} @@ -31,7 +36,12 @@ {{ 'finding.description' | translate }} @@ -40,7 +50,12 @@ {{ 'finding.impact' | translate }} diff --git a/security-c4po-angular/src/app/pentest/pentest-content/pentest-findings/pentest-findings.component.scss b/security-c4po-angular/src/app/pentest/pentest-content/pentest-findings/pentest-findings.component.scss index c6e06cc..7183cab 100644 --- a/security-c4po-angular/src/app/pentest/pentest-content/pentest-findings/pentest-findings.component.scss +++ b/security-c4po-angular/src/app/pentest/pentest-content/pentest-findings/pentest-findings.component.scss @@ -1,4 +1,5 @@ @import '../../../../assets/@theme/styles/themes'; +@import '../../../../assets/@theme/styles/_text-overflow.scss'; .finding-table { margin-right: 2rem; diff --git a/security-c4po-angular/src/assets/i18n/de-DE.json b/security-c4po-angular/src/assets/i18n/de-DE.json index 462ed99..71510eb 100644 --- a/security-c4po-angular/src/assets/i18n/de-DE.json +++ b/security-c4po-angular/src/assets/i18n/de-DE.json @@ -78,6 +78,7 @@ "languageLabel": "Sprache ändern:", "password": { "title": "Passwort ändern:", + "button" : "Passwort ändern", "old": "Altes Passwort", "new": "Neues Passwort", "confirmNew": "Neues Passwort bestätigen", diff --git a/security-c4po-angular/src/assets/i18n/en-US.json b/security-c4po-angular/src/assets/i18n/en-US.json index 5f4cda4..e8dbd0f 100644 --- a/security-c4po-angular/src/assets/i18n/en-US.json +++ b/security-c4po-angular/src/assets/i18n/en-US.json @@ -78,6 +78,7 @@ "languageLabel": "Change language:", "password": { "title": "Change password:", + "button" : "Change password", "old": "Old password", "new": "New password", "confirmNew": "Confirm new password", diff --git a/security-c4po-angular/src/shared/functions/sort-names.function.ts b/security-c4po-angular/src/shared/functions/sort-names.function.ts new file mode 100644 index 0000000..c3da6d2 --- /dev/null +++ b/security-c4po-angular/src/shared/functions/sort-names.function.ts @@ -0,0 +1,3 @@ +export function sortDescending(nameOne: string, nameTwo: string): number { + return nameOne === nameTwo ? 0 : (nameOne > nameTwo ? 1 : -1); +} diff --git a/security-c4po-angular/src/shared/modules/profile-settings/password-input-from/password-input-from.component.html b/security-c4po-angular/src/shared/modules/profile-settings/password-input-from/password-input-from.component.html index 246a99d..140e6e0 100644 --- a/security-c4po-angular/src/shared/modules/profile-settings/password-input-from/password-input-from.component.html +++ b/security-c4po-angular/src/shared/modules/profile-settings/password-input-from/password-input-from.component.html @@ -11,16 +11,15 @@ class="form-field" [status]="passwordFormGroup.get('oldPassword').dirty ? (passwordFormGroup.get('oldPassword').invalid ? 'danger' : 'basic') : 'basic'" placeholder="{{'******'}}"> - - - + + *ngIf="oldPasswordCtrl.hasError('required')"> {{'profile.password.validationMessage.passwordRequired' | translate}} - +
@@ -34,18 +33,17 @@ class="form-field" [status]="passwordFormGroup.get('newPassword').dirty ? (passwordFormGroup.get('newPassword').invalid ? 'danger' : 'basic') : 'basic'" placeholder="{{'******'}}"> - - - + + *ngIf="newPasswordCtrl.hasError('required')"> {{'profile.password.validationMessage.passwordRequired' | translate}} - + - +
diff --git a/security-c4po-angular/src/shared/modules/profile-settings/password-input-from/password-input-from.component.scss b/security-c4po-angular/src/shared/modules/profile-settings/password-input-from/password-input-from.component.scss index ff567b1..7433f56 100644 --- a/security-c4po-angular/src/shared/modules/profile-settings/password-input-from/password-input-from.component.scss +++ b/security-c4po-angular/src/shared/modules/profile-settings/password-input-from/password-input-from.component.scss @@ -16,6 +16,10 @@ margin-bottom: 0.5rem; } + .form-field:disabled { + background-color: nb-theme(color-basic-transparent-focus); + } + .form-field-button { margin-top: 1rem; margin-right: 1rem; diff --git a/security-c4po-angular/src/shared/modules/profile-settings/password-input-from/password-input-from.component.ts b/security-c4po-angular/src/shared/modules/profile-settings/password-input-from/password-input-from.component.ts index dd7e8dd..5eb2b3d 100644 --- a/security-c4po-angular/src/shared/modules/profile-settings/password-input-from/password-input-from.component.ts +++ b/security-c4po-angular/src/shared/modules/profile-settings/password-input-from/password-input-from.component.ts @@ -1,5 +1,14 @@ import {Component, EventEmitter, forwardRef, Input, OnInit, Output} from '@angular/core'; -import {AbstractControl, FormBuilder, FormControl, FormGroup, NG_VALIDATORS, NG_VALUE_ACCESSOR, ValidationErrors} from '@angular/forms'; +import { + AbstractControl, + FormBuilder, + FormControl, + FormGroup, + NG_VALIDATORS, + NG_VALUE_ACCESSOR, + ValidationErrors, + Validators +} from '@angular/forms'; import { OldPasswordEmptyError, PasswordErrorStateMatcher @@ -61,9 +70,9 @@ export class PasswordInputFromComponent implements OnInit { ngOnInit(): void { this.passwordFormGroup = this.fb.group( { - oldPassword: ['', [PasswordInputFromComponent.containsBlankSpaceValidator]], - newPassword: ['', [PasswordInputFromComponent.containsBlankSpaceValidator]], - confirmNewPassword: '' + oldPassword: [{value: '', disabled: true}, [Validators.required, PasswordInputFromComponent.containsBlankSpaceValidator]], + newPassword: [{value: '', disabled: true}, [Validators.required, PasswordInputFromComponent.containsBlankSpaceValidator]], + confirmNewPassword: [{value: '', disabled: true}, [Validators.required]] }, {validators: [passwordValidator]} ); diff --git a/security-c4po-angular/src/shared/modules/profile-settings/profile-settings.component.html b/security-c4po-angular/src/shared/modules/profile-settings/profile-settings.component.html index 7e9ab93..d6817c0 100644 --- a/security-c4po-angular/src/shared/modules/profile-settings/profile-settings.component.html +++ b/security-c4po-angular/src/shared/modules/profile-settings/profile-settings.component.html @@ -36,21 +36,15 @@ type="text" required id="firstName" nbInput fullWidth - class="form-field" + class="form-field name" [status]="userFormGroup.get('firstName').dirty ? (userFormGroup.get('firstName').invalid ? 'danger' : 'basic') : 'basic'" placeholder="{{'profile.firstName.placeholder' | translate}} *"> - - + - {{'WWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWW'}} + *ngIf="userFirstNameControl.hasError('required')"> {{'profile.validationMessage.firstNameRequired' | translate}} - - {{'Firstname is invalid' | translate}} - - + @@ -61,60 +55,66 @@ type="text" required id="lastName" nbInput fullWidth - class="form-field" + class="form-field name" [status]="userFormGroup.get('lastName').dirty ? (userFormGroup.get('lastName').invalid ? 'danger' : 'basic') : 'basic'" placeholder="{{'profile.lastName.placeholder' | translate}} *"> - - + + *ngIf="userLastNameControl.hasError('required')"> {{'profile.validationMessage.lastNameRequired' | translate}} - - {{'Lastname is invalid' | translate}} - - + -
- - -
- - - - - - - - +
+
+ + +
+ + + +
-
- -
- -
-
- - - +
+ + +
+ + + + + + + + +
diff --git a/security-c4po-angular/src/shared/modules/profile-settings/profile-settings.component.scss b/security-c4po-angular/src/shared/modules/profile-settings/profile-settings.component.scss index 513074a..6c9f570 100644 --- a/security-c4po-angular/src/shared/modules/profile-settings/profile-settings.component.scss +++ b/security-c4po-angular/src/shared/modules/profile-settings/profile-settings.component.scss @@ -3,7 +3,7 @@ .profile-setting-dialog { width: 45.25rem !important; - height: 46rem; + height: 32rem; .dialog-header { height: 8vh; @@ -54,6 +54,10 @@ width: 30rem; } + .name { + width: 14.5rem !important; + } + .error-text { float: left; color: nb-theme(color-danger-default); @@ -62,7 +66,7 @@ } .language-settings{ - padding-top: 2rem; + padding-top: 2.5rem; .language-selection-label { font-weight: bold; @@ -76,6 +80,7 @@ } .languageContainer { + padding-top: 1rem; display: flex; max-width: 8rem; min-width: 8rem; @@ -88,11 +93,22 @@ } .user-password-change{ - padding-top: 1rem; + padding-top: 2rem; .password-selection-label { font-weight: bold; } + + .password-form { + padding-top: 1rem; + + .password-btn { + .btn-icon { + padding-bottom: 0.15rem; + padding-right: 0.5rem; + } + } + } } } } diff --git a/security-c4po-angular/src/shared/modules/profile-settings/profile-settings.component.ts b/security-c4po-angular/src/shared/modules/profile-settings/profile-settings.component.ts index dc41068..b6f2e5e 100644 --- a/security-c4po-angular/src/shared/modules/profile-settings/profile-settings.component.ts +++ b/security-c4po-angular/src/shared/modules/profile-settings/profile-settings.component.ts @@ -92,8 +92,8 @@ export class ProfileSettingsComponent implements OnInit { setupUserFormGroup(): void { this.userFormGroup = this.fb.group({ username: [{value: '', disabled: true}, [Validators.required, Validators.pattern(Patterns.NO_WHITESPACES)]], - firstName: [{value: '', disabled: false}, [Validators.required, Validators.pattern(Patterns.NO_WHITESPACES)]], - lastName: [{value: '', disabled: false}, [Validators.required, Validators.pattern(Patterns.NO_WHITESPACES)]], + firstName: [{value: '', disabled: true}, [Validators.required, Validators.pattern(Patterns.NO_WHITESPACES)]], + lastName: [{value: '', disabled: true}, [Validators.required, Validators.pattern(Patterns.NO_WHITESPACES)]], eMail: [{value: '', disabled: true}, [Validators.required, Validators.email, Validators.pattern(Patterns.NO_WHITESPACES)]], avatarUploader: null }); @@ -112,6 +112,13 @@ export class ProfileSettingsComponent implements OnInit { this.userPasswordInputControl = this.passwordFormGroup.get('passwordInput'); } + changePasswordInKeycloak(): void { + this.userService.redirectToChangePasswordAction().then(r => { + // tslint:disable-next-line:no-console + console.info('Redirecting to Keycloak for password change...'); + }); + } + onClickLanguage(language: string): void { this.translateService.use(language); } @@ -149,22 +156,20 @@ export class ProfileSettingsComponent implements OnInit { } private handleUserUpdate(user: User): Observable { - /* return this.userService.updateUser(user, this.timeOfChange) - .pipe( - tap({ - next: resultingUser => { - this.store.dispatch(new UpdateUserSettings(resultingUser)); - this.store.dispatch(new UpdateUser(resultingUser, true)); - }, - error: error => { - console.error(error); - this.onFailedUpdate(error); - } - }), - mapTo(void 0), - untilDestroyed(this) - );*/ - return of(); + return this.userService.changeUserProperties(user) + .pipe( + tap({ + next: resultingUser => { + this.store.dispatch(new UpdateUserSettings(resultingUser)); + this.store.dispatch(new UpdateUser(resultingUser, true)); + }, + error: error => { + console.error(error); + } + }), + mapTo(void 0), + untilDestroyed(this) + ); } private handlePasswordChange(): void { diff --git a/security-c4po-angular/src/shared/services/api/pentest.service.ts b/security-c4po-angular/src/shared/services/api/pentest.service.ts index 0bcadc3..0b8bc42 100644 --- a/security-c4po-angular/src/shared/services/api/pentest.service.ts +++ b/security-c4po-angular/src/shared/services/api/pentest.service.ts @@ -61,7 +61,6 @@ export class PentestService { templatePentests[i]?.childEntries?.forEach((childEntry: Pentest) => { // ToDo: Add only child entrys that are not included in response aka available pentests if (!availablePentests.map(it => it.refNumber).includes(childEntry.refNumber)) { - console.log('Child entry from template: ', childEntry); availablePentests[indexOfPentestWithChildEntries].childEntries.push(childEntry); } else { // Removes the pentest from availablePentests and add it as a child entry diff --git a/security-c4po-angular/src/shared/services/user-service/user.service.ts b/security-c4po-angular/src/shared/services/user-service/user.service.ts index 0f6f38a..2722c7b 100644 --- a/security-c4po-angular/src/shared/services/user-service/user.service.ts +++ b/security-c4po-angular/src/shared/services/user-service/user.service.ts @@ -7,12 +7,15 @@ import {KeycloakService} from 'keycloak-angular'; import {map} from 'rxjs/operators'; import {environment} from '../../../environments/environment'; import {Route} from '@shared/models/route.enum'; +import {Project} from '@shared/models/project.model'; @Injectable({ providedIn: 'root' }) export class UserService { + private keycloakBaseURL = `${environment.keycloakURL}/`; + constructor(private http: HttpClient, private keycloakService: KeycloakService, private store: Store) { @@ -56,25 +59,22 @@ export class UserService { // https://stackoverflow.com/questions/33910615/is-there-an-api-call-for-changing-user-password-on-keycloak // ToDo: https://www.keycloak.org/docs/latest/server_development/ - public changeUserProperties(): Observable { + public changeUserProperties(user: User): Observable { // ToDo: There is a kc_action parameter available in keycloak to let application force required actions. + console.warn(user); /*../realms/myrealm/protocol/openid-connect/auth ?response_type=code &client_id=myclient &redirect_uri=https://myclient.com &kc_action=update_profile*/ - return of(); + return of(user); } - // ToDo: https://keycloak.discourse.group/t/integrate-change-password-from-account-console-into-own-webapp/12300 - public changePassword(): Observable { - // ToDo: To force (or allow) a password update, use kc_action=UPDATE_PASSWORD - /*../realms/myrealm/protocol/openid-connect/auth - ?response_type=code - &client_id=myclient - &redirect_uri=https://myclient.com - &kc_action=update_profile*/ - return of(); + public redirectToChangePasswordAction(): Promise { + // https://keycloak.discourse.group/t/integrate-change-password-from-account-console-into-own-webapp/12300 + return this.keycloakService.login({ + action: 'UPDATE_PASSWORD', + }); } private getToken(): Observable { diff --git a/security-c4po-angular/src/shared/widgets/comment-widget/comment-widget.component.html b/security-c4po-angular/src/shared/widgets/comment-widget/comment-widget.component.html index 0589e8f..92eb0ad 100644 --- a/security-c4po-angular/src/shared/widgets/comment-widget/comment-widget.component.html +++ b/security-c4po-angular/src/shared/widgets/comment-widget/comment-widget.component.html @@ -4,6 +4,7 @@ {{numberOfComments}} - {{'-'}} + + {{0}}
diff --git a/security-c4po-angular/src/shared/widgets/findig-widget/findig-widget.component.html b/security-c4po-angular/src/shared/widgets/findig-widget/findig-widget.component.html index 4c6de06..c208cf7 100644 --- a/security-c4po-angular/src/shared/widgets/findig-widget/findig-widget.component.html +++ b/security-c4po-angular/src/shared/widgets/findig-widget/findig-widget.component.html @@ -4,6 +4,7 @@ {{numberOfFindings}} - {{'-'}} + + {{0}}
diff --git a/security-c4po-angular/src/shared/widgets/project-widget/project-widget.component.html b/security-c4po-angular/src/shared/widgets/project-widget/project-widget.component.html index 982a1d4..f6e36d5 100644 --- a/security-c4po-angular/src/shared/widgets/project-widget/project-widget.component.html +++ b/security-c4po-angular/src/shared/widgets/project-widget/project-widget.component.html @@ -37,8 +37,9 @@
+ [displayValue]="project.testingProgress > 25"> {{'popup.info' | translate}} {{'global.no.progress' | translate}}
-
+
/ diff --git a/security-c4po-angular/src/app/objective-overview/objective-table/objective-table.component.ts b/security-c4po-angular/src/app/objective-overview/objective-table/objective-table.component.ts index d56211d..08ce411 100644 --- a/security-c4po-angular/src/app/objective-overview/objective-table/objective-table.component.ts +++ b/security-c4po-angular/src/app/objective-overview/objective-table/objective-table.component.ts @@ -1,5 +1,5 @@ import {Component, OnInit} from '@angular/core'; -import {NbGetters, NbSortDirection, NbSortRequest, NbTreeGridDataSource, NbTreeGridDataSourceBuilder} from '@nebular/theme'; +import {NbGetters, NbTreeGridDataSource, NbTreeGridDataSourceBuilder} from '@nebular/theme'; import {ObjectiveEntry, Pentest, transformPentestsToObjectiveEntries} from '@shared/models/pentest.model'; import {PentestService} from '@shared/services/api/pentest.service'; import {Store} from '@ngxs/store'; @@ -15,6 +15,7 @@ import * as FA from '@fortawesome/free-solid-svg-icons'; import {DialogService} from '@shared/services/dialog-service/dialog.service'; import {NotificationService, PopupType} from '@shared/services/toaster-service/notification.service'; import {Project} from '@shared/models/project.model'; +import {sortDescending} from '@shared/functions/sort-names.function'; @UntilDestroy() @Component({ @@ -25,7 +26,6 @@ import {Project} from '@shared/models/project.model'; export class ObjectiveTableComponent implements OnInit { // HTML only readonly fa = FA; - // use ban and check loading$: BehaviorSubject = new BehaviorSubject(true); columns: Array = [ @@ -71,12 +71,6 @@ export class ObjectiveTableComponent implements OnInit { } }); this.loadPentestData(); - this.changeSortTable() - this.dataSource.sort({column: ObjectiveColumns.TEST_ID, direction: NbSortDirection.DESCENDING}); - } - - private changeSortTable(): void { - this.dataSource.sort({column: ObjectiveColumns.TEST_ID, direction: NbSortDirection.DESCENDING}); } loadPentestData(): void { @@ -87,8 +81,12 @@ export class ObjectiveTableComponent implements OnInit { untilDestroyed(this) ).subscribe({ next: (pentests: Pentest[]) => { - this.pentests$.next(pentests); - this.data = transformPentestsToObjectiveEntries(pentests); + // Sort data without before adding as table data source + const sortedPentests = pentests.sort((a: Pentest, b: Pentest) => + sortDescending(a.refNumber.toLowerCase(), b.refNumber.toLowerCase()) + ); + this.pentests$.next(sortedPentests); + this.data = transformPentestsToObjectiveEntries(sortedPentests); this.dataSource.setData(this.data, this.getters); this.loading$.next(false); }, diff --git a/security-c4po-angular/src/app/pentest/pentest-content/pentest-comments/pentest-comments.component.html b/security-c4po-angular/src/app/pentest/pentest-content/pentest-comments/pentest-comments.component.html index 619c68b..5aeb7bd 100644 --- a/security-c4po-angular/src/app/pentest/pentest-content/pentest-comments/pentest-comments.component.html +++ b/security-c4po-angular/src/app/pentest/pentest-content/pentest-comments/pentest-comments.component.html @@ -11,7 +11,12 @@ {{ 'comment.title' | translate }}
- {{ comment.data['title'] }} + + {{ comment.data['title'] }} + + + {{ comment.data['title'].slice(0, 200) + '...' }} + - {{ comment.data['description'] }} + + {{ comment.data['description'] }} + + + {{ comment.data['description'].slice(0, 200) + '...' }} + - {{ finding.data['title'] }} + + {{ finding.data['title'] }} + + + {{ finding.data['title'].slice(0, 200) + '...' }} + - {{ finding.data['description'] }} + + {{ finding.data['description'] }} + + + {{ finding.data['description'].slice(0, 200) + '...' }} + - {{ finding.data['impact'] }} + + {{ finding.data['impact'] }} + + + {{ finding.data['impact'].slice(0, 200) + '...' }} +