diff --git a/console/src/app/pages/orgs/org-create/org-create.component.html b/console/src/app/pages/orgs/org-create/org-create.component.html index 26f4667929..266e41b919 100644 --- a/console/src/app/pages/orgs/org-create/org-create.component.html +++ b/console/src/app/pages/orgs/org-create/org-create.component.html @@ -47,11 +47,11 @@

{{ 'USER.CREATE.NAMEANDEMAILSECTION' | translate }}

- {{ 'USER.PROFILE.USERNAME' | translate }} - - - {{ 'USER.VALIDATION.REQUIRED' | translate }} - + {{ 'USER.PROFILE.USERNAME' | translate }} + + + {{ 'USER.VALIDATION.REQUIRED' | translate }} + {{ 'USER.PROFILE.EMAIL' | translate }} @@ -113,25 +113,52 @@ {{ 'USER.PASSWORD.NEW' | translate }} - {{ 'USER.VALIDATION.REQUIRED' | translate }} + + + {{ 'USER.VALIDATION.REQUIRED' | translate }} - {{ policy | passwordPattern | translate }} + + {{ 'USER.VALIDATION.SYMBOLERROR' | translate }} + + + {{ 'USER.VALIDATION.NUMBERERROR' | translate }} + + + {{ 'USER.VALIDATION.UPPERCASEMISSING' | translate }} + + + {{ 'USER.VALIDATION.LOWERCASEMISSING' | translate }} - {{ 'USER.VALIDATION.MINLENGTH' | translate:policy }} + {{ 'USER.VALIDATION.MINLENGTH' | translate:password?.errors?.minlength }} {{ 'USER.PASSWORD.CONFIRM' | translate }} - + + {{ 'USER.VALIDATION.REQUIRED' | translate }} - {{ policy | passwordPattern | translate }} + + {{ 'USER.VALIDATION.SYMBOLERROR' | translate }} - - {{ 'USER.VALIDATION.MINLENGTH' | translate:policy }} + + {{ 'USER.VALIDATION.NUMBERERROR' | translate }} + + + {{ 'USER.PASSWORD.NOTEQUAL' | translate }} + + + {{ 'USER.VALIDATION.UPPERCASEMISSING' | translate }} + + + {{ 'USER.VALIDATION.LOWERCASEMISSING' | translate }} + + + {{ 'USER.VALIDATION.MINLENGTH' | translate:confirmPassword?.errors?.minlength }} @@ -150,4 +177,4 @@ {{'CONTINUE' | translate}} -
+ \ No newline at end of file diff --git a/console/src/app/pages/orgs/org-create/org-create.component.ts b/console/src/app/pages/orgs/org-create/org-create.component.ts index 7c4f97ce5e..e358ffbe02 100644 --- a/console/src/app/pages/orgs/org-create/org-create.component.ts +++ b/console/src/app/pages/orgs/org-create/org-create.component.ts @@ -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 { diff --git a/console/src/app/pages/user-create/user-create.component.html b/console/src/app/pages/user-create/user-create.component.html index 7e482d87ec..7533095e35 100644 --- a/console/src/app/pages/user-create/user-create.component.html +++ b/console/src/app/pages/user-create/user-create.component.html @@ -13,7 +13,7 @@

{{ 'USER.CREATE.DESCRIPTION' | translate }}

-
+

{{ 'USER.CREATE.NAMEANDEMAILSECTION' | translate }}

@@ -30,6 +30,9 @@ {{ 'USER.VALIDATION.REQUIRED' | translate }} + + {{ 'USER.VALIDATION.NOEMAIL' | translate }} + {{ 'USER.PROFILE.FIRSTNAME' | translate }} diff --git a/console/src/app/pages/user-create/user-create.component.ts b/console/src/app/pages/user-create/user-create.component.ts index f8b72eda2d..98c47ad78e 100644 --- a/console/src/app/pages/user-create/user-create.component.ts +++ b/console/src/app/pages/user-create/user-create.component.ts @@ -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: [''], diff --git a/console/src/app/pages/user-detail/auth-user-detail/auth-user-detail.component.html b/console/src/app/pages/user-detail/auth-user-detail/auth-user-detail.component.html index ce2fc8055f..0790fd1dc7 100644 --- a/console/src/app/pages/user-detail/auth-user-detail/auth-user-detail.component.html +++ b/console/src/app/pages/user-detail/auth-user-detail/auth-user-detail.component.html @@ -6,6 +6,20 @@ {{ 'USER.PAGES.NOUSER' | translate }} +
+ + + + + + + + +
+ + -
- - - - - - - - -
@@ -47,27 +49,52 @@ {{ 'USER.PASSWORD.NEW' | translate }} - {{ 'USER.VALIDATION.REQUIRED' | translate }} + + + {{ 'USER.VALIDATION.REQUIRED' | translate }} - {{ policy | passwordPattern | translate }} + + {{ 'USER.VALIDATION.SYMBOLERROR' | translate }} + + + {{ 'USER.VALIDATION.NUMBERERROR' | translate }} + + + {{ 'USER.VALIDATION.UPPERCASEMISSING' | translate }} + + + {{ 'USER.VALIDATION.LOWERCASEMISSING' | translate }} - {{ 'USER.VALIDATION.MINLENGTH' | translate:policy }} + {{ 'USER.VALIDATION.MINLENGTH' | translate:newPassword?.errors?.minlength }} +
{{ 'USER.PASSWORD.CONFIRM' | translate }} - {{ 'USER.VALIDATION.REQUIRED' | translate }} + + + {{ 'USER.VALIDATION.REQUIRED' | translate }} - - {{ policy | passwordPattern | translate }} + + {{ 'USER.VALIDATION.SYMBOLERROR' | translate }} + + + {{ 'USER.VALIDATION.NUMBERERROR' | translate }} + + + {{ 'USER.PASSWORD.NOTEQUAL' | translate }} + + + {{ 'USER.VALIDATION.UPPERCASEMISSING' | translate }} + + + {{ 'USER.VALIDATION.LOWERCASEMISSING' | translate }} - {{ 'USER.VALIDATION.MINLENGTH' | translate:policy }} - - {{ 'USER.PASSWORD.NOTEQUAL' | translate }} + {{ 'USER.VALIDATION.MINLENGTH' | translate:confirmPassword?.errors?.minlength }}
diff --git a/console/src/app/pages/user-detail/auth-user-detail/auth-user-detail.component.scss b/console/src/app/pages/user-detail/auth-user-detail/auth-user-detail.component.scss index ca08eba518..8d861c004c 100644 --- a/console/src/app/pages/user-detail/auth-user-detail/auth-user-detail.component.scss +++ b/console/src/app/pages/user-detail/auth-user-detail/auth-user-detail.component.scss @@ -143,6 +143,7 @@ h1 { flex-wrap: wrap; align-items: stretch; margin: -.5rem; + app-card { flex: 1; margin: .5rem diff --git a/console/src/app/pages/user-detail/auth-user-detail/auth-user-detail.component.ts b/console/src/app/pages/user-detail/auth-user-detail/auth-user-detail.component.ts index 1eb2939fad..d826926a55 100644 --- a/console/src/app/pages/user-detail/auth-user-detail/auth-user-detail.component.ts +++ b/console/src/app/pages/user-detail/auth-user-detail/auth-user-detail.component.ts @@ -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); diff --git a/console/src/app/pages/user-detail/auth-user-mfa/auth-user-mfa.component.html b/console/src/app/pages/user-detail/auth-user-mfa/auth-user-mfa.component.html index 3023d642da..2435627827 100644 --- a/console/src/app/pages/user-detail/auth-user-mfa/auth-user-mfa.component.html +++ b/console/src/app/pages/user-detail/auth-user-mfa/auth-user-mfa.component.html @@ -7,6 +7,7 @@ delete_outline +

{{error}}

- + diff --git a/console/src/app/pages/user-detail/user-detail/user-detail.component.ts b/console/src/app/pages/user-detail/user-detail/user-detail.component.ts index 195c0e60d1..8680edd282 100644 --- a/console/src/app/pages/user-detail/user-detail/user-detail.component.ts +++ b/console/src/app/pages/user-detail/user-detail/user-detail.component.ts @@ -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({ diff --git a/console/src/app/pages/user-detail/user-mfa/user-mfa.component.html b/console/src/app/pages/user-detail/user-mfa/user-mfa.component.html index 8f9b00ff2f..bb6d1c4b63 100644 --- a/console/src/app/pages/user-detail/user-mfa/user-mfa.component.html +++ b/console/src/app/pages/user-detail/user-mfa/user-mfa.component.html @@ -4,6 +4,7 @@ {{'USER.MFA.TYPE.'+ mfa.type | translate}} {{'USER.MFA.STATE.'+ mfa.state | translate}} +

{{error}}

diff --git a/console/src/app/pages/user-detail/user-mfa/user-mfa.component.ts b/console/src/app/pages/user-detail/user-mfa/user-mfa.component.ts index 0a574e47f3..6bd144c10e 100644 --- a/console/src/app/pages/user-detail/user-mfa/user-mfa.component.ts +++ b/console/src/app/pages/user-detail/user-mfa/user-mfa.component.ts @@ -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); - // }); - // } - // } } diff --git a/console/src/app/pages/user-detail/validators.ts b/console/src/app/pages/user-detail/validators.ts new file mode 100644 index 0000000000..e435620480 --- /dev/null +++ b/console/src/app/pages/user-detail/validators.ts @@ -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, + }, + }; +} diff --git a/console/src/app/pipes/password-pattern.pipe.spec.ts b/console/src/app/pipes/password-pattern.pipe.spec.ts deleted file mode 100644 index 1253c24a00..0000000000 --- a/console/src/app/pipes/password-pattern.pipe.spec.ts +++ /dev/null @@ -1,8 +0,0 @@ -import { PasswordPatternPipe } from './password-pattern.pipe'; - -describe('PasswordPatternPipe', () => { - it('create an instance', () => { - const pipe = new PasswordPatternPipe(); - expect(pipe).toBeTruthy(); - }); -}); diff --git a/console/src/app/pipes/password-pattern.pipe.ts b/console/src/app/pipes/password-pattern.pipe.ts deleted file mode 100644 index cc604df3ec..0000000000 --- a/console/src/app/pipes/password-pattern.pipe.ts +++ /dev/null @@ -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); - } - -} diff --git a/console/src/app/pipes/pipes.module.ts b/console/src/app/pipes/pipes.module.ts index 910f8d73c2..976c10f054 100644 --- a/console/src/app/pipes/pipes.module.ts +++ b/console/src/app/pipes/pipes.module.ts @@ -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 { } diff --git a/console/src/app/services/org.service.ts b/console/src/app/services/org.service.ts index 0cf123f265..81961612bf 100644 --- a/console/src/app/services/org.service.ts +++ b/console/src/app/services/org.service.ts @@ -12,6 +12,7 @@ import { OrgDomainSearchQuery, OrgDomainSearchRequest, OrgDomainSearchResponse, + OrgIamPolicy, OrgID, OrgMemberRoles, OrgMemberSearchRequest, @@ -198,6 +199,14 @@ export class OrgService { // Policy + public async GetMyOrgIamPolicy(): Promise { + return await this.request( + c => c.getMyOrgIamPolicy, + new Empty(), + f => f, + ); + } + public async GetPasswordAgePolicy(): Promise { const req = new Empty(); diff --git a/console/src/assets/i18n/de.json b/console/src/assets/i18n/de.json index 77b7a19218..fa27a77eb6 100644 --- a/console/src/assets/i18n/de.json +++ b/console/src/assets/i18n/de.json @@ -164,7 +164,12 @@ "VALIDATION": { "INVALIDPATTERN": "Das Password muss aus mindestens 8 Zeichen bestehen und einen Grossbuchstaben, ein Sonderzeichen und eine Zahl enthalten. Die maximale Anzahl an Zeichen ist 72!", "REQUIRED": "Das Feld ist leer", - "MINLENGTH":"Das Password muss mindestens {{minLength}} Zeichen lang sein!" + "MINLENGTH":"Das Password muss mindestens {{requiredLength}} Zeichen lang sein!", + "NOEMAIL":"Username darf keine email sein!", + "UPPERCASEMISSING":"Password muss einen Großbuchstaben beinhalten", + "LOWERCASEMISSING":"Password muss einen Kleinbuchstaben beinhalten", + "SYMBOLERROR":"Das Password muss ein Symbol beinhalten!", + "NUMBERERROR":"Das Password muss eine Nummer beinhalten!" }, "STATE": { "0":"unbekannt", @@ -287,9 +292,9 @@ "PROJECT": { "PAGES": { "TITLE": "Projekt", - "DESCRIPTION": "Hier können Sie wichtige Einstellungen prüfen und die Daten einsehen, mit denen das der Dienst konfiguriert worden ist", + "DESCRIPTION": "Hier können Sie wichtige Einstellungen prüfen und die Daten einsehen, mit denen der Dienst konfiguriert worden ist", "LIST": "Projekte", - "LISTDESCRIPTION":"Hier finden Sie alle Projekte, für die Sie Aktionen anzeigen oder ausführen dürfen. Wenn Sie kein Projekt finden können, wenden Sie sich an einen Projektbesitzer oder an jemanden mit den entsprechenden Rechten, um Projektzugriff zu erhalten.", + "LISTDESCRIPTION":"Hier finden Sie alle Projekte, für die Sie Aktionen anzeigen oder ausführen dürfen. Wenn Sie Ihr Projekt nicht finden können, wenden Sie sich an einen Projektbesitzer oder an jemanden mit den entsprechenden Rechten, um Projektzugriff zu erhalten.", "DETAIL": "Detail", "CREATE": "Projekt erstellen", "CREATE_DESC": "Geben Sie den Namen ein", diff --git a/console/src/assets/i18n/en.json b/console/src/assets/i18n/en.json index a2bb38369c..c398d6916e 100644 --- a/console/src/assets/i18n/en.json +++ b/console/src/assets/i18n/en.json @@ -52,7 +52,7 @@ "DETAIL": "Detail", "CREATE": "Create", "MY": "My Informations", - "LOGINNAMES":"Login names", + "LOGINNAMES":"Loginnames", "LOGINNAMESDESC":"You can log into zitadel with these names", "COPY":"Copy to clipboard", "COPIED":"Copied to clipboard!", @@ -164,7 +164,12 @@ "VALIDATION": { "INVALIDPATTERN": "The password must consist of at least 8 characters and contain a capital letter, a special character and a number. The maximum length is 72.", "REQUIRED": "The input field is empty", - "MINLENGTH":"The password has to be at least {{minLength}} characters long!" + "MINLENGTH":"The password has to be at least {{requiredLength}} characters long!", + "NOEMAIL":"Username can not be an email", + "UPPERCASEMISSING":"An uppercase character is needed!", + "LOWERCASEMISSING":"A lowercase character is needed!", + "SYMBOLERROR":"The password must include a symbol!", + "NUMBERERROR":"The password must include a number!" }, "STATE": { "0":"unbekannt", @@ -223,7 +228,6 @@ "SYMBOLERROR":"The password must include a symbol!", "NUMBERERROR":"The password must include a number!", "PATTERNERROR":"The required pattern is not fulfilled!" - }, "PWD_AGE": { "TITLE":"Password Age",