fix(console): password validation hints, mfa, i18n (#265)

* proto gen

* fix: remove type from project lists (#256)

* fix: remove type from project lists

* Update user-detail.component.ts

* fix: remove add project

Co-authored-by: Livio Amstutz <[email protected]>

* fix project view model

* regen mgmt proto

* rm orgid from route, switch to project view

* chore(deps-dev): bump @types/jasmine from 3.5.10 to 3.5.11 in /console (#252)

Bumps [@types/jasmine](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/jasmine) from 3.5.10 to 3.5.11.
- [Release notes](https://github.com/DefinitelyTyped/DefinitelyTyped/releases)
- [Commits](https://github.com/DefinitelyTyped/DefinitelyTyped/commits/HEAD/types/jasmine)

Signed-off-by: dependabot[bot] <[email protected]>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* chore(deps-dev): bump @angular-devkit/build-angular in /console (#251)

Bumps [@angular-devkit/build-angular](https://github.com/angular/angular-cli) from 0.901.7 to 0.901.9.
- [Release notes](https://github.com/angular/angular-cli/releases)
- [Commits](https://github.com/angular/angular-cli/commits)

Signed-off-by: dependabot[bot] <[email protected]>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* chore(deps): bump moment from 2.26.0 to 2.27.0 in /console (#250)

Bumps [moment](https://github.com/moment/moment) from 2.26.0 to 2.27.0.
- [Release notes](https://github.com/moment/moment/releases)
- [Changelog](https://github.com/moment/moment/blob/develop/CHANGELOG.md)
- [Commits](https://github.com/moment/moment/compare/2.26.0...2.27.0)

Signed-off-by: dependabot[bot] <[email protected]>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* chore(deps-dev): bump karma from 5.0.9 to 5.1.0 in /console (#218)

Bumps [karma](https://github.com/karma-runner/karma) from 5.0.9 to 5.1.0.
- [Release notes](https://github.com/karma-runner/karma/releases)
- [Changelog](https://github.com/karma-runner/karma/blob/master/CHANGELOG.md)
- [Commits](https://github.com/karma-runner/karma/compare/v5.0.9...v5.1.0)

Signed-off-by: dependabot[bot] <[email protected]>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* chore(deps): bump ngx-moment from 3.5.0 to 4.0.1 in /console (#219)

Bumps [ngx-moment](https://github.com/urish/ngx-moment) from 3.5.0 to 4.0.1.
- [Release notes](https://github.com/urish/ngx-moment/releases)
- [Changelog](https://github.com/urish/ngx-moment/blob/master/CHANGELOG.md)
- [Commits](https://github.com/urish/ngx-moment/compare/3.5.0...4.0.1)

Signed-off-by: dependabot[bot] <[email protected]>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Max Peintner <[email protected]>

* chore(deps-dev): bump @angular/language-service in /console (#217)

Bumps [@angular/language-service](https://github.com/angular/angular/tree/HEAD/packages/language-service) from 9.1.10 to 9.1.11.
- [Release notes](https://github.com/angular/angular/releases)
- [Changelog](https://github.com/angular/angular/blob/master/CHANGELOG.md)
- [Commits](https://github.com/angular/angular/commits/9.1.11/packages/language-service)

Signed-off-by: dependabot[bot] <[email protected]>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Max Peintner <[email protected]>

* chore(deps-dev): bump @angular/cli from 9.1.7 to 9.1.9 in /console (#249)

Bumps [@angular/cli](https://github.com/angular/angular-cli) from 9.1.7 to 9.1.9.
- [Release notes](https://github.com/angular/angular-cli/releases)
- [Commits](https://github.com/angular/angular-cli/compare/v9.1.7...v9.1.9)

Signed-off-by: dependabot[bot] <[email protected]>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Max Peintner <[email protected]>

* set partial user profile

* fix org routing

* auth user loginnames, i18n

* fix clipboard, secret regeneration

* project role required field

* show change editor

* show granted project grid, remove add button

* hide meta overflow

* username validation

* common pwd validators

* fix org create pwd validation

* show 2fa error

* i18n

Co-authored-by: Fabi <[email protected]>
Co-authored-by: Livio Amstutz <[email protected]>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
This commit is contained in:
Max Peintner
2020-06-24 11:33:27 +02:00
committed by GitHub
co-authored by dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Fabi Livio Amstutz dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
parent f7aed1c864
commit aa0510aa3d
21 changed files with 291 additions and 126 deletions
@@ -47,11 +47,11 @@
<div class="content">
<p class="section">{{ 'USER.CREATE.NAMEANDEMAILSECTION' | translate }}</p>
<mat-form-field class="formfield">
<mat-label>{{ 'USER.PROFILE.USERNAME' | translate }}</mat-label>
<input matInput formControlName="userName" required />
<mat-error *ngIf="userName?.invalid && userName?.errors?.required">
{{ 'USER.VALIDATION.REQUIRED' | translate }}
</mat-error>
<mat-label>{{ 'USER.PROFILE.USERNAME' | translate }}</mat-label>
<input matInput formControlName="userName" required />
<mat-error *ngIf="userName?.invalid && userName?.errors?.required">
{{ 'USER.VALIDATION.REQUIRED' | translate }}
</mat-error>
</mat-form-field>
<mat-form-field class="formfield">
<mat-label>{{ 'USER.PROFILE.EMAIL' | translate }}</mat-label>
@@ -113,25 +113,52 @@
<mat-label>{{ 'USER.PASSWORD.NEW' | translate }}</mat-label>
<input autocomplete="off" name="firstpassword" matInput formControlName="password"
type="password" />
<mat-error *ngIf="password?.errors?.required">{{ 'USER.VALIDATION.REQUIRED' | translate }}
<mat-error *ngIf="password?.errors?.required">
{{ 'USER.VALIDATION.REQUIRED' | translate }}
</mat-error>
<mat-error *ngIf="password?.errors?.pattern">{{ policy | passwordPattern | translate }}
<mat-error *ngIf="password?.errors?.symbolValidator">
{{ 'USER.VALIDATION.SYMBOLERROR' | translate }}
</mat-error>
<mat-error *ngIf="password?.errors?.numberValidator">
{{ 'USER.VALIDATION.NUMBERERROR' | translate }}
</mat-error>
<mat-error *ngIf="password?.errors?.upperCaseValidator">
{{ 'USER.VALIDATION.UPPERCASEMISSING' | translate }}
</mat-error>
<mat-error *ngIf="password?.errors?.lowerCaseValidator">
{{ 'USER.VALIDATION.LOWERCASEMISSING' | translate }}
</mat-error>
<mat-error *ngIf="password?.errors?.minlength">
{{ 'USER.VALIDATION.MINLENGTH' | translate:policy }}
{{ 'USER.VALIDATION.MINLENGTH' | translate:password?.errors?.minlength }}
</mat-error>
</mat-form-field>
<mat-form-field class="formfield">
<mat-label>{{ 'USER.PASSWORD.CONFIRM' | translate }}</mat-label>
<input autocomplete="off" name="firstpasswordRepeat" matInput formControlName="confirmPassword"
<input autocomplete="off" name="confirmPassword" matInput formControlName="confirmPassword"
type="password" />
<mat-error *ngIf="confirmPassword?.errors?.required">
{{ 'USER.VALIDATION.REQUIRED' | translate }}
</mat-error>
<mat-error *ngIf="password?.errors?.pattern">{{ policy | passwordPattern | translate }}
<mat-error *ngIf="confirmPassword?.errors?.symbolValidator">
{{ 'USER.VALIDATION.SYMBOLERROR' | translate }}
</mat-error>
<mat-error *ngIf="password?.errors?.minlength">
{{ 'USER.VALIDATION.MINLENGTH' | translate:policy }}
<mat-error *ngIf="confirmPassword?.errors?.numberValidator">
{{ 'USER.VALIDATION.NUMBERERROR' | translate }}
</mat-error>
<mat-error *ngIf="confirmPassword?.errors?.notequal">
{{ 'USER.PASSWORD.NOTEQUAL' | translate }}
</mat-error>
<mat-error *ngIf="confirmPassword?.errors?.upperCaseValidator">
{{ 'USER.VALIDATION.UPPERCASEMISSING' | translate }}
</mat-error>
<mat-error *ngIf="confirmPassword?.errors?.lowerCaseValidator">
{{ 'USER.VALIDATION.LOWERCASEMISSING' | translate }}
</mat-error>
<mat-error *ngIf="confirmPassword?.errors?.minlength">
{{ 'USER.VALIDATION.MINLENGTH' | translate:confirmPassword?.errors?.minlength }}
</mat-error>
</mat-form-field>
@@ -150,4 +177,4 @@
{{'CONTINUE' | translate}}
</button>
</ng-container>
</div>
</div>
@@ -9,6 +9,8 @@ import { AdminService } from 'src/app/services/admin.service';
import { OrgService } from 'src/app/services/org.service';
import { ToastService } from 'src/app/services/toast.service';
import { lowerCaseValidator, numberValidator, symbolValidator, upperCaseValidator } from '../../user-detail/validators';
function passwordConfirmValidator(c: AbstractControl): any {
if (!c.parent || !c) {
return;
@@ -20,7 +22,12 @@ function passwordConfirmValidator(c: AbstractControl): any {
return;
}
if (pwd.value !== cpwd.value) {
return { invalid: true };
return {
invalid: true,
notequal: {
valid: false,
},
};
}
}
@@ -69,16 +76,16 @@ export class OrgCreateComponent {
validators.push(Validators.minLength(this.policy.minLength));
}
if (this.policy.hasLowercase) {
validators.push(Validators.pattern(/[a-z]/g));
validators.push(lowerCaseValidator);
}
if (this.policy.hasUppercase) {
validators.push(Validators.pattern(/[A-Z]/g));
validators.push(upperCaseValidator);
}
if (this.policy.hasNumber) {
validators.push(Validators.pattern(/[0-9]/g));
validators.push(numberValidator);
}
if (this.policy.hasSymbol) {
validators.push(Validators.pattern(/[^a-z0-9]/gi));
validators.push(symbolValidator);
}
this.userForm = this.fb.group({
@@ -154,7 +161,7 @@ export class OrgCreateComponent {
}
public get userName(): AbstractControl | null {
return this.userForm.get('userName');
return this.userForm.get('userName');
}
public get firstName(): AbstractControl | null {
@@ -13,7 +13,7 @@
<p class="desc">{{ 'USER.CREATE.DESCRIPTION' | translate }}</p>
</div>
<form [formGroup]="userForm" (ngSubmit)="createUser()" class="form">
<form *ngIf="userForm" [formGroup]="userForm" (ngSubmit)="createUser()" class="form">
<!-- <h2>{{ 'USER.PAGES.CREATE' | translate}}</h2> -->
<div class="content">
<p class="section">{{ 'USER.CREATE.NAMEANDEMAILSECTION' | translate }}</p>
@@ -30,6 +30,9 @@
<mat-error *ngIf="userName?.invalid && userName?.errors?.required">
{{ 'USER.VALIDATION.REQUIRED' | translate }}
</mat-error>
<mat-error *ngIf="userName?.invalid && userName?.errors?.noEmailValidator">
{{ 'USER.VALIDATION.NOEMAIL' | translate }}
</mat-error>
</mat-form-field>
<mat-form-field class="formfield">
<mat-label>{{ 'USER.PROFILE.FIRSTNAME' | translate }}</mat-label>
@@ -4,8 +4,27 @@ import { Router } from '@angular/router';
import { Subscription } from 'rxjs';
import { CreateUserRequest, Gender, User } from 'src/app/proto/generated/management_pb';
import { MgmtUserService } from 'src/app/services/mgmt-user.service';
import { OrgService } from 'src/app/services/org.service';
import { ToastService } from 'src/app/services/toast.service';
function noEmailValidator(c: AbstractControl): any {
const EMAIL_REGEXP: RegExp = /^((?!@).)*$/gm;
if (!c.parent || !c) {
return;
}
const username = c.parent.get('userName');
if (!username) {
return;
}
return EMAIL_REGEXP.test(username.value) ? null : {
noEmailValidator: {
valid: false,
},
};
}
@Component({
selector: 'app-user-create',
templateUrl: './user-create.component.html',
@@ -19,12 +38,35 @@ export class UserCreateComponent implements OnDestroy {
private sub: Subscription = new Subscription();
constructor(private router: Router, private toast: ToastService, public userService: MgmtUserService,
private fb: FormBuilder) {
public userLoginMustBeDomain: boolean = false;
constructor(
private router: Router,
private toast: ToastService,
public userService: MgmtUserService,
private fb: FormBuilder,
private orgService: OrgService,
) {
this.orgService.GetMyOrgIamPolicy().then((iampolicy) => {
this.userLoginMustBeDomain = iampolicy.toObject().userLoginMustBeDomain;
console.log(this.userLoginMustBeDomain);
this.initForm();
}).catch(error => {
console.error(error);
this.initForm();
});
}
private initForm(): void {
this.userForm = this.fb.group({
email: ['', [Validators.required, Validators.email]],
userName: ['', [Validators.required, Validators.minLength(2)]],
userName: ['',
[
Validators.required,
Validators.minLength(2),
this.userLoginMustBeDomain ? noEmailValidator : Validators.email,
],
],
firstName: ['', Validators.required],
lastName: ['', Validators.required],
nickName: [''],
@@ -6,6 +6,20 @@
<span *ngIf="!loading && !user">{{ 'USER.PAGES.NOUSER' | translate }}</span>
<div class="col" *ngIf="user">
<app-card title="{{ 'USER.PROFILE.TITLE' | translate }}"
description="{{'USER.PROFILE.DESCRIPTION' | translate}}">
<app-detail-form [genders]="genders" [languages]="languages" [profile]="user"
(changedLanguage)="changedLanguage($event)" (submitData)="saveProfile($event)">
</app-detail-form>
</app-card>
<app-card title="Theme" class="theme-card">
<app-theme-setting></app-theme-setting>
</app-card>
</div>
<app-card title="{{ 'USER.PAGES.LOGINNAMES' | translate }}"
description="{{ 'USER.PAGES.LOGINNAMESDESC' | translate }}" *ngIf="user">
<div class="login-name-row" *ngFor="let login of user?.loginNamesList">
@@ -19,18 +33,6 @@
</div>
</app-card>
<div class="col" *ngIf="user">
<app-card title="{{ 'USER.PROFILE.TITLE' | translate }}"
description="{{'USER.PROFILE.DESCRIPTION' | translate}}">
<app-detail-form [genders]="genders" [languages]="languages" [profile]="user"
(changedLanguage)="changedLanguage($event)" (submitData)="saveProfile($event)">
</app-detail-form>
</app-card>
<app-card title="Theme" class="theme-card">
<app-theme-setting></app-theme-setting>
</app-card>
</div>
<app-card *ngIf="user" title="{{'USER.PASSWORD.TITLE' | translate}}"
description="{{'USER.PASSWORD.DESCRIPTION' | translate}}">
@@ -47,27 +49,52 @@
<mat-label>{{ 'USER.PASSWORD.NEW' | translate }}</mat-label>
<input autocomplete="off" name="new password" type="password" matInput
formControlName="newPassword" />
<mat-error *ngIf="newPassword?.errors?.required">{{ 'USER.VALIDATION.REQUIRED' | translate }}
<mat-error *ngIf="newPassword?.errors?.required">
{{ 'USER.VALIDATION.REQUIRED' | translate }}
</mat-error>
<mat-error *ngIf="newPassword?.errors?.pattern">{{ policy | passwordPattern | translate }}
<mat-error *ngIf="newPassword?.errors?.symbolValidator">
{{ 'USER.VALIDATION.SYMBOLERROR' | translate }}
</mat-error>
<mat-error *ngIf="newPassword?.errors?.numberValidator">
{{ 'USER.VALIDATION.NUMBERERROR' | translate }}
</mat-error>
<mat-error *ngIf="newPassword?.errors?.upperCaseValidator">
{{ 'USER.VALIDATION.UPPERCASEMISSING' | translate }}
</mat-error>
<mat-error *ngIf="newPassword?.errors?.lowerCaseValidator">
{{ 'USER.VALIDATION.LOWERCASEMISSING' | translate }}
</mat-error>
<mat-error *ngIf="newPassword?.errors?.minlength">
{{ 'USER.VALIDATION.MINLENGTH' | translate:policy }}
{{ 'USER.VALIDATION.MINLENGTH' | translate:newPassword?.errors?.minlength }}
</mat-error>
</mat-form-field>
<mat-form-field class="formfield">
<mat-label>{{ 'USER.PASSWORD.CONFIRM' | translate }}</mat-label>
<input autocomplete="off" name="password repeating" type="password" matInput
formControlName="confirmPassword" />
<mat-error *ngIf="confirmPassword?.errors?.required">{{ 'USER.VALIDATION.REQUIRED' | translate }}
<mat-error *ngIf="confirmPassword?.errors?.required">
{{ 'USER.VALIDATION.REQUIRED' | translate }}
</mat-error>
<mat-error *ngIf="confirmPassword?.errors?.pattern">
{{ policy | passwordPattern | translate }}
<mat-error *ngIf="confirmPassword?.errors?.symbolValidator">
{{ 'USER.VALIDATION.SYMBOLERROR' | translate }}
</mat-error>
<mat-error *ngIf="confirmPassword?.errors?.numberValidator">
{{ 'USER.VALIDATION.NUMBERERROR' | translate }}
</mat-error>
<mat-error *ngIf="confirmPassword?.errors?.notequal">
{{ 'USER.PASSWORD.NOTEQUAL' | translate }}
</mat-error>
<mat-error *ngIf="confirmPassword?.errors?.upperCaseValidator">
{{ 'USER.VALIDATION.UPPERCASEMISSING' | translate }}
</mat-error>
<mat-error *ngIf="confirmPassword?.errors?.lowerCaseValidator">
{{ 'USER.VALIDATION.LOWERCASEMISSING' | translate }}
</mat-error>
<mat-error *ngIf="confirmPassword?.errors?.minlength">
{{ 'USER.VALIDATION.MINLENGTH' | translate:policy }}
</mat-error>
<mat-error *ngIf="confirmPassword?.errors?.notequal">{{ 'USER.PASSWORD.NOTEQUAL' | translate }}
{{ 'USER.VALIDATION.MINLENGTH' | translate:confirmPassword?.errors?.minlength }}
</mat-error>
</mat-form-field>
</div>
@@ -143,6 +143,7 @@ h1 {
flex-wrap: wrap;
align-items: stretch;
margin: -.5rem;
app-card {
flex: 1;
margin: .5rem
@@ -10,6 +10,7 @@ import { OrgService } from 'src/app/services/org.service';
import { ToastService } from 'src/app/services/toast.service';
import { CodeDialogComponent } from '../code-dialog/code-dialog.component';
import { lowerCaseValidator, numberValidator, symbolValidator, upperCaseValidator } from '../validators';
function passwordConfirmValidator(c: AbstractControl): any {
if (!c.parent || !c) {
@@ -22,7 +23,12 @@ function passwordConfirmValidator(c: AbstractControl): any {
return;
}
if (pwd.value !== cpwd.value) {
return { invalid: true, notequal: 'Password is not equal' };
return {
invalid: true,
notequal: {
valid: false,
},
};
}
}
@@ -51,6 +57,8 @@ export class AuthUserDetailComponent implements OnDestroy {
public policy!: PasswordComplexityPolicy.AsObject;
public copied: string = '';
public userLoginMustBeDomain: boolean = false;
constructor(
public translate: TranslateService,
private toast: ToastService,
@@ -67,16 +75,16 @@ export class AuthUserDetailComponent implements OnDestroy {
validators.push(Validators.minLength(this.policy.minLength));
}
if (this.policy.hasLowercase) {
validators.push(Validators.pattern(/[a-z]/g));
validators.push(lowerCaseValidator);
}
if (this.policy.hasUppercase) {
validators.push(Validators.pattern(/[A-Z]/g));
validators.push(upperCaseValidator);
}
if (this.policy.hasNumber) {
validators.push(Validators.pattern(/[0-9]/g));
validators.push(numberValidator);
}
if (this.policy.hasSymbol) {
validators.push(Validators.pattern(/[^a-z0-9]/gi));
validators.push(symbolValidator);
}
this.passwordForm = this.fb.group({
@@ -84,6 +92,11 @@ export class AuthUserDetailComponent implements OnDestroy {
newPassword: ['', validators],
confirmPassword: ['', [...validators, passwordConfirmValidator]],
});
this.passwordForm.controls['newPassword'].valueChanges.subscribe(() => {
console.log(this.passwordForm.controls['newPassword'].errors);
});
}).catch(error => {
this.toast.showError(error.message);
console.error(error.message);
@@ -7,6 +7,7 @@
<mat-icon>delete_outline</mat-icon>
</button>
</div>
<p class="row" *ngIf="error">{{error}}</p>
</div>
<div class="add-row">
<button (click)="addOTP()" mat-stroked-button color="primary" matTooltip="{{'ACTIONS.NEW' | translate}}">
@@ -19,6 +19,8 @@ export class AuthUserMfaComponent implements OnInit, OnDestroy {
public MfaType: any = MfaType;
public MFAState: any = MFAState;
public error: string = '';
constructor(private userService: AuthUserService, private toast: ToastService, private dialog: MatDialog) { }
public ngOnInit(): void {
@@ -55,10 +57,9 @@ export class AuthUserMfaComponent implements OnInit, OnDestroy {
public getOTP(): void {
this.userService.GetMyMfas().then(mfas => {
this.mfaSubject.next(mfas.toObject().mfasList);
console.log(mfas.toObject());
}).catch(error => {
console.error(error);
this.toast.showError(error.message);
this.error = error.message;
});
}
@@ -4,6 +4,7 @@ import { Subscription } from 'rxjs';
import { Gender as authGender, UserProfile as authUP } from 'src/app/proto/generated/auth_pb';
import { Gender as mgmtGender, UserProfile as mgmtUP } from 'src/app/proto/generated/management_pb';
@Component({
selector: 'app-detail-form',
templateUrl: './detail-form.component.html',
@@ -23,7 +24,9 @@ export class DetailFormComponent implements OnInit, OnDestroy {
constructor(private fb: FormBuilder) {
this.profileForm = this.fb.group({
userName: [{ value: '', disabled: true }, [Validators.required]],
userName: [{ value: '', disabled: true }, [
Validators.required,
]],
firstName: [{ value: '', disabled: this.disabled }, Validators.required],
lastName: [{ value: '', disabled: this.disabled }, Validators.required],
nickName: [{ value: '', disabled: this.disabled }],
@@ -33,32 +33,55 @@
</card-actions>
<form *ngIf="passwordForm" autocomplete="new-password" [formGroup]="passwordForm"
(ngSubmit)="setInitialPassword()">
<!-- {{USERSTATE_INITIAL}} -->
<div class="content center">
<mat-form-field class="formfield">
<mat-label>{{ 'USER.PASSWORD.NEW' | translate }}</mat-label>
<input autocomplete="off" name="password" matInput formControlName="password" type="password" />
<mat-error *ngIf="password?.errors?.required">{{ 'USER.VALIDATION.REQUIRED' | translate }}
<mat-error *ngIf="password?.errors?.required">
{{ 'USER.VALIDATION.REQUIRED' | translate }}
</mat-error>
<mat-error *ngIf="password?.errors?.symbolValidator">
{{ 'USER.VALIDATION.SYMBOLERROR' | translate }}
</mat-error>
<mat-error *ngIf="password?.errors?.numberValidator">
{{ 'USER.VALIDATION.NUMBERERROR' | translate }}
</mat-error>
<mat-error *ngIf="password?.errors?.upperCaseValidator">
{{ 'USER.VALIDATION.UPPERCASEMISSING' | translate }}
</mat-error>
<mat-error *ngIf="password?.errors?.lowerCaseValidator">
{{ 'USER.VALIDATION.LOWERCASEMISSING' | translate }}
</mat-error>
<mat-error *ngIf="password?.errors?.minlength">
{{ 'USER.VALIDATION.MINLENGTH' | translate: policy }}
</mat-error>
<mat-error *ngIf="password?.errors?.pattern">{{ policy | passwordPattern | translate }}
{{ 'USER.VALIDATION.MINLENGTH' | translate:password?.errors?.minlength }}
</mat-error>
</mat-form-field>
<mat-form-field class="formfield">
<mat-label>{{ 'USER.PASSWORD.CONFIRM' | translate }}</mat-label>
<input autocomplete="off" name="passwordRepeat" matInput formControlName="confirmPassword"
type="password" />
<mat-error *ngIf="confirmPassword?.errors?.required">
{{ 'USER.VALIDATION.REQUIRED' | translate }}
</mat-error>
<mat-error *ngIf="confirmPassword?.errors?.symbolValidator">
{{ 'USER.VALIDATION.SYMBOLERROR' | translate }}
</mat-error>
<mat-error *ngIf="confirmPassword?.errors?.numberValidator">
{{ 'USER.VALIDATION.NUMBERERROR' | translate }}
</mat-error>
<mat-error *ngIf="confirmPassword?.errors?.notequal">
{{ 'USER.PASSWORD.NOTEQUAL' | translate }}
</mat-error>
<mat-error *ngIf="confirmPassword?.errors?.upperCaseValidator">
{{ 'USER.VALIDATION.UPPERCASEMISSING' | translate }}
</mat-error>
<mat-error *ngIf="confirmPassword?.errors?.lowerCaseValidator">
{{ 'USER.VALIDATION.LOWERCASEMISSING' | translate }}
</mat-error>
<mat-error *ngIf="confirmPassword?.errors?.minlength">
{{ 'USER.VALIDATION.MINLENGTH' | translate: policy }}
</mat-error>
<mat-error *ngIf="confirmPassword?.errors?.pattern">{{ policy | passwordPattern | translate }}
</mat-error>
<mat-error *ngIf="confirmPassword?.errors?.notequal">{{ 'USER.PASSWORD.NOTEQUAL' | translate }}
{{ 'USER.VALIDATION.MINLENGTH' | translate:confirmPassword?.errors?.minlength }}
</mat-error>
</mat-form-field>
</div>
@@ -151,7 +174,7 @@
</div>
</app-card>
<app-auth-user-mfa *ngIf="user" [user]="user"></app-auth-user-mfa>
<app-user-mfa *ngIf="user" [user]="user"></app-user-mfa>
<app-card title="{{ 'USER.ADDRESS.TITLE' | translate }}">
<form [formGroup]="addressForm" (ngSubmit)="saveAddress()">
@@ -23,6 +23,7 @@ import { OrgService } from 'src/app/services/org.service';
import { ToastService } from 'src/app/services/toast.service';
import { CodeDialogComponent } from '../code-dialog/code-dialog.component';
import { lowerCaseValidator, numberValidator, symbolValidator, upperCaseValidator } from '../validators';
function passwordConfirmValidator(c: AbstractControl): any {
if (!c.parent || !c) {
@@ -84,16 +85,16 @@ export class UserDetailComponent implements OnInit, OnDestroy {
validators.push(Validators.minLength(this.policy.minLength));
}
if (this.policy.hasLowercase) {
validators.push(Validators.pattern(/[a-z]/g));
validators.push(lowerCaseValidator);
}
if (this.policy.hasUppercase) {
validators.push(Validators.pattern(/[A-Z]/g));
validators.push(upperCaseValidator);
}
if (this.policy.hasNumber) {
validators.push(Validators.pattern(/[0-9]/g));
validators.push(numberValidator);
}
if (this.policy.hasSymbol) {
validators.push(Validators.pattern(/[^a-z0-9]/gi));
validators.push(symbolValidator);
}
this.passwordForm = this.fb.group({
@@ -4,6 +4,7 @@
<span>{{'USER.MFA.TYPE.'+ mfa.type | translate}}</span>
<span>{{'USER.MFA.STATE.'+ mfa.state | translate}}</span>
</div>
<p class="row" *ngIf="error">{{error}}</p>
</div>
<div class="table-wrapper">
<div class="spinner-container" *ngIf="loading$ | async">
@@ -2,7 +2,6 @@ import { Component, Input, OnDestroy, OnInit } from '@angular/core';
import { BehaviorSubject, Observable } from 'rxjs';
import { MFAState, MfaType, MultiFactor, UserView } from 'src/app/proto/generated/management_pb';
import { MgmtUserService } from 'src/app/services/mgmt-user.service';
import { ToastService } from 'src/app/services/toast.service';
export interface MFAItem {
@@ -23,11 +22,11 @@ export class UserMfaComponent implements OnInit, OnDestroy {
public MfaType: any = MfaType;
public MFAState: any = MFAState;
constructor(private mgmtUserService: MgmtUserService,
private toast: ToastService) { }
public error: string = '';
constructor(private mgmtUserService: MgmtUserService) { }
public ngOnInit(): void {
console.log(this.user);
this.getOTP();
}
@@ -37,31 +36,12 @@ export class UserMfaComponent implements OnInit, OnDestroy {
}
public getOTP(): void {
console.log('otp', this.user);
this.mgmtUserService.getUserMfas(this.user.id).then(mfas => {
this.mfaSubject.next(mfas.toObject().mfasList);
console.log(mfas.toObject());
this.error = '';
}).catch(error => {
console.error(error);
this.toast.showError(error.message);
this.error = error.message;
});
}
// public deleteMFA(type: MfaType): void {
// if (type === MfaType.MFATYPE_OTP) {
// this.userService.RemoveMfaOTP().then(() => {
// this.toast.showInfo('OTP Deleted');
// const index = this.mfaSubject.value.findIndex(mfa => mfa.type === type);
// if (index > -1) {
// const newValues = this.mfaSubject.value;
// newValues.splice(index, 1);
// this.mfaSubject.next(newValues);
// }
// }).catch(error => {
// this.toast.showError(error.message);
// });
// }
// }
}
@@ -0,0 +1,45 @@
import { FormControl } from '@angular/forms';
export function symbolValidator(c: FormControl): any {
const REGEXP = /[^a-z0-9]/gi;
return REGEXP.test(c.value) ? null : {
invalid: true,
symbolValidator: {
valid: false,
},
};
}
export function numberValidator(c: FormControl): any {
const REGEXP = /[0-9]/g;
return REGEXP.test(c.value) ? null : {
invalid: true,
numberValidator: {
valid: false,
},
};
}
export function upperCaseValidator(c: FormControl): any {
const REGEXP = /[A-Z]/g;
return REGEXP.test(c.value) ? null : {
invalid: true,
upperCaseValidator: {
valid: false,
},
};
}
export function lowerCaseValidator(c: FormControl): any {
const REGEXP = /[a-z]/g;
return REGEXP.test(c.value) ? null : {
invalid: true,
lowerCaseValidator: {
valid: false,
},
};
}
@@ -1,8 +0,0 @@
import { PasswordPatternPipe } from './password-pattern.pipe';
describe('PasswordPatternPipe', () => {
it('create an instance', () => {
const pipe = new PasswordPatternPipe();
expect(pipe).toBeTruthy();
});
});
@@ -1,17 +0,0 @@
import { Pipe, PipeTransform } from '@angular/core';
import { PasswordComplexityPolicy } from '../proto/generated/management_pb';
import { OrgService } from '../services/org.service';
@Pipe({
name: 'passwordPattern',
})
export class PasswordPatternPipe implements PipeTransform {
constructor(private orgService: OrgService) { }
transform(policy: PasswordComplexityPolicy.AsObject, ...args: unknown[]): string {
return this.orgService.getLocalizedComplexityPolicyPatternErrorString(policy);
}
}
-3
View File
@@ -3,13 +3,11 @@ import { NgModule } from '@angular/core';
import { MomentModule } from 'ngx-moment';
import { LocalizedDatePipe } from './localized-date.pipe';
import { PasswordPatternPipe } from './password-pattern.pipe';
@NgModule({
declarations: [
LocalizedDatePipe,
PasswordPatternPipe,
],
imports: [
CommonModule,
@@ -17,7 +15,6 @@ import { PasswordPatternPipe } from './password-pattern.pipe';
],
exports: [
LocalizedDatePipe,
PasswordPatternPipe,
],
})
export class PipesModule { }
+9
View File
@@ -12,6 +12,7 @@ import {
OrgDomainSearchQuery,
OrgDomainSearchRequest,
OrgDomainSearchResponse,
OrgIamPolicy,
OrgID,
OrgMemberRoles,
OrgMemberSearchRequest,
@@ -198,6 +199,14 @@ export class OrgService {
// Policy
public async GetMyOrgIamPolicy(): Promise<OrgIamPolicy> {
return await this.request(
c => c.getMyOrgIamPolicy,
new Empty(),
f => f,
);
}
public async GetPasswordAgePolicy(): Promise<PasswordAgePolicy> {
const req = new Empty();