From 60ed67d004acb78041efa9e2a2d20cd83611e803 Mon Sep 17 00:00:00 2001 From: mehmet-erim Date: Wed, 30 Oct 2019 09:06:02 +0300 Subject: [PATCH 1/5] feat(account): implement dynamic password validation to register page #2039 --- .../components/register/register.component.ts | 37 +++++++++++++++++-- 1 file changed, 33 insertions(+), 4 deletions(-) diff --git a/npm/ng-packs/packages/account/src/lib/components/register/register.component.ts b/npm/ng-packs/packages/account/src/lib/components/register/register.component.ts index 01b0377def..e01287e1cb 100644 --- a/npm/ng-packs/packages/account/src/lib/components/register/register.component.ts +++ b/npm/ng-packs/packages/account/src/lib/components/register/register.component.ts @@ -1,6 +1,6 @@ -import { ConfigState, GetAppConfiguration } from '@abp/ng.core'; +import { ConfigState, GetAppConfiguration, ABP } from '@abp/ng.core'; import { ToasterService } from '@abp/ng.theme.shared'; -import { Component } from '@angular/core'; +import { Component, OnInit } from '@angular/core'; import { FormBuilder, FormGroup, Validators } from '@angular/forms'; import { Navigate } from '@ngxs/router-plugin'; import { Store } from '@ngxs/store'; @@ -10,13 +10,14 @@ import { catchError, finalize, switchMap, take, tap } from 'rxjs/operators'; import snq from 'snq'; import { RegisterRequest } from '../../models'; import { AccountService } from '../../services/account.service'; +import { PasswordRules, validatePassword } from '@ngx-validate/core'; const { maxLength, minLength, required, email } = Validators; @Component({ selector: 'abp-register', templateUrl: './register.component.html', }) -export class RegisterComponent { +export class RegisterComponent implements OnInit { form: FormGroup; inProgress: boolean; @@ -30,10 +31,38 @@ export class RegisterComponent { ) { this.oauthService.configure(this.store.selectSnapshot(ConfigState.getOne('environment')).oAuthConfig); this.oauthService.loadDiscoveryDocument(); + } + + ngOnInit() { + const passwordRules: ABP.Dictionary = this.store.selectSnapshot( + ConfigState.getSettings('Identity.Password'), + ); + const passwordRulesArr = [] as PasswordRules; + let requiredLength = 1; + + if ((passwordRules['Abp.Identity.Password.RequireDigit'] || '').toLowerCase() === 'true') { + passwordRulesArr.push('number'); + } + + if ((passwordRules['Abp.Identity.Password.RequireLowercase'] || '').toLowerCase() === 'true') { + passwordRulesArr.push('small'); + } + + if ((passwordRules['Abp.Identity.Password.RequireUppercase'] || '').toLowerCase() === 'true') { + passwordRulesArr.push('capital'); + } + + if (+(passwordRules['Abp.Identity.Password.RequiredUniqueChars'] || 0) > 0) { + passwordRulesArr.push('special'); + } + + if (Number.isInteger(+passwordRules['Abp.Identity.Password.RequiredLength'])) { + requiredLength = +passwordRules['Abp.Identity.Password.RequiredLength']; + } this.form = this.fb.group({ username: ['', [required, maxLength(255)]], - password: ['', [required, maxLength(32)]], + password: ['', [required, validatePassword(passwordRulesArr), minLength(requiredLength), maxLength(32)]], email: ['', [required, email]], }); } From 7d026e5e9176511864947ebc8d8c452384e72ee9 Mon Sep 17 00:00:00 2001 From: mehmet-erim Date: Wed, 30 Oct 2019 09:10:25 +0300 Subject: [PATCH 2/5] feat(identity): implement dynamic password validation to users page #2039 --- .../lib/components/users/users.component.ts | 44 +++++++++++++++++-- 1 file changed, 40 insertions(+), 4 deletions(-) diff --git a/npm/ng-packs/packages/identity/src/lib/components/users/users.component.ts b/npm/ng-packs/packages/identity/src/lib/components/users/users.component.ts index cee9b2306f..4574aee2df 100644 --- a/npm/ng-packs/packages/identity/src/lib/components/users/users.component.ts +++ b/npm/ng-packs/packages/identity/src/lib/components/users/users.component.ts @@ -1,4 +1,4 @@ -import { ABP } from '@abp/ng.core'; +import { ABP, ConfigState } from '@abp/ng.core'; import { ConfirmationService, Toaster } from '@abp/ng.theme.shared'; import { Component, TemplateRef, TrackByFunction, ViewChild, OnInit } from '@angular/core'; import { AbstractControl, FormArray, FormBuilder, FormGroup, Validators, FormControl } from '@angular/forms'; @@ -17,6 +17,7 @@ import { } from '../../actions/identity.actions'; import { Identity } from '../../models/identity'; import { IdentityState } from '../../states/identity.state'; +import { PasswordRules, validatePassword } from '@ngx-validate/core'; @Component({ selector: 'abp-users', templateUrl: './users.component.html', @@ -55,6 +56,10 @@ export class UsersComponent implements OnInit { sortKey = ''; + passwordRulesArr = [] as PasswordRules; + + requiredPasswordLength = 1; + trackByFn: TrackByFunction = (index, item) => Object.keys(item)[0] || index; get roleGroups(): FormGroup[] { @@ -65,6 +70,30 @@ export class UsersComponent implements OnInit { ngOnInit() { this.get(); + + const passwordRules: ABP.Dictionary = this.store.selectSnapshot( + ConfigState.getSettings('Identity.Password'), + ); + + if ((passwordRules['Abp.Identity.Password.RequireDigit'] || '').toLowerCase() === 'true') { + this.passwordRulesArr.push('number'); + } + + if ((passwordRules['Abp.Identity.Password.RequireLowercase'] || '').toLowerCase() === 'true') { + this.passwordRulesArr.push('small'); + } + + if ((passwordRules['Abp.Identity.Password.RequireUppercase'] || '').toLowerCase() === 'true') { + this.passwordRulesArr.push('capital'); + } + + if (+(passwordRules['Abp.Identity.Password.RequiredUniqueChars'] || 0) > 0) { + this.passwordRulesArr.push('special'); + } + + if (Number.isInteger(+passwordRules['Abp.Identity.Password.RequiredLength'])) { + this.requiredPasswordLength = +passwordRules['Abp.Identity.Password.RequiredLength']; + } } onSearch(value) { @@ -92,10 +121,17 @@ export class UsersComponent implements OnInit { ), }); + const passwordValidators = [ + validatePassword(this.passwordRulesArr), + Validators.minLength(this.requiredPasswordLength), + Validators.maxLength(32), + ]; + + this.form.addControl('password', new FormControl('', [...passwordValidators])); + if (!this.selected.userName) { - this.form.addControl('password', new FormControl('', [Validators.required, Validators.maxLength(32)])); - } else { - this.form.addControl('password', new FormControl('', [Validators.maxLength(32)])); + this.form.get('password').setValidators([...passwordValidators, Validators.required]); + this.form.get('password').updateValueAndValidity(); } }); } From f34ef20bcdee0e75ab391199a9ad98244e057f7c Mon Sep 17 00:00:00 2001 From: mehmet-erim Date: Wed, 30 Oct 2019 09:14:18 +0300 Subject: [PATCH 3/5] refactor(account): add maxLength to change password fields resolves #2039 --- npm/ng-packs/package.json | 2 +- .../components/change-password/change-password.component.ts | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/npm/ng-packs/package.json b/npm/ng-packs/package.json index 37611e8293..2bc4fec54a 100644 --- a/npm/ng-packs/package.json +++ b/npm/ng-packs/package.json @@ -5,7 +5,7 @@ "test": "ng test", "symlink": "symlink", "abpng": "abpng", - "commit": "git-cz && node scripts/push.js", + "commit": "git-cz", "lint": "ng lint --fix", "scripts:build": "cd scripts && npm install && npm run build" }, diff --git a/npm/ng-packs/packages/account/src/lib/components/change-password/change-password.component.ts b/npm/ng-packs/packages/account/src/lib/components/change-password/change-password.component.ts index 850e4e37a1..a1a0a51216 100644 --- a/npm/ng-packs/packages/account/src/lib/components/change-password/change-password.component.ts +++ b/npm/ng-packs/packages/account/src/lib/components/change-password/change-password.component.ts @@ -7,7 +7,7 @@ import { Store } from '@ngxs/store'; import snq from 'snq'; import { finalize } from 'rxjs/operators'; -const { minLength, required } = Validators; +const { minLength, required, maxLength } = Validators; const PASSWORD_FIELDS = ['newPassword', 'repeatNewPassword']; @@ -61,12 +61,12 @@ export class ChangePasswordComponent implements OnInit { newPassword: [ '', { - validators: [required, validatePassword(passwordRulesArr), minLength(requiredLength)], + validators: [required, validatePassword(passwordRulesArr), minLength(requiredLength), maxLength(32)], }, ], repeatNewPassword: [ '', - { validators: [required, validatePassword(passwordRulesArr), minLength(requiredLength)] }, + { validators: [required, validatePassword(passwordRulesArr), minLength(requiredLength), maxLength(32)] }, ], }, { From 335c74d80097de5a97913e97230f423768f751ea Mon Sep 17 00:00:00 2001 From: mehmet-erim Date: Wed, 30 Oct 2019 09:54:30 +0300 Subject: [PATCH 4/5] fix(identity): validation display error --- .../identity/src/lib/components/users/users.component.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/npm/ng-packs/packages/identity/src/lib/components/users/users.component.html b/npm/ng-packs/packages/identity/src/lib/components/users/users.component.html index 6afa1b7f4c..92e7dd5773 100644 --- a/npm/ng-packs/packages/identity/src/lib/components/users/users.component.html +++ b/npm/ng-packs/packages/identity/src/lib/components/users/users.component.html @@ -115,7 +115,7 @@ - +

{{ (selected?.id ? 'AbpIdentity::Edit' : 'AbpIdentity::NewUser') | abpLocalization }}

From 48fe815634317e6e3c4425a240e2584f400806d0 Mon Sep 17 00:00:00 2001 From: mehmet-erim Date: Wed, 30 Oct 2019 10:30:22 +0300 Subject: [PATCH 5/5] chore: update npm versions --- npm/ng-packs/package.json | 28 +++++++++---------- .../packages/theme-shared/package.json | 6 ++-- templates/app/angular/package.json | 26 ++++++++--------- 3 files changed, 30 insertions(+), 30 deletions(-) diff --git a/npm/ng-packs/package.json b/npm/ng-packs/package.json index 2bc4fec54a..1875b16ac9 100644 --- a/npm/ng-packs/package.json +++ b/npm/ng-packs/package.json @@ -19,20 +19,20 @@ "@abp/ng.tenant-management.config": "^1.0.2", "@abp/ng.theme.shared": "^1.0.2", "@angular-builders/jest": "^8.2.0", - "@angular-devkit/build-angular": "~0.803.6", - "@angular-devkit/build-ng-packagr": "~0.803.6", - "@angular/animations": "~8.2.8", - "@angular/cdk": "^8.0.1", - "@angular/cli": "~8.3.6", - "@angular/common": "~8.1.2", - "@angular/compiler": "~8.2.8", - "@angular/compiler-cli": "~8.2.8", - "@angular/core": "~8.1.2", - "@angular/forms": "~8.1.2", - "@angular/language-service": "~8.2.8", - "@angular/platform-browser": "~8.2.8", - "@angular/platform-browser-dynamic": "~8.2.8", - "@angular/router": "~8.1.2", + "@angular-devkit/build-angular": "~0.803.15", + "@angular-devkit/build-ng-packagr": "~0.803.15", + "@angular/animations": "~8.2.12", + "@angular/cdk": "^8.2.3", + "@angular/cli": "~8.3.15", + "@angular/common": "~8.2.12", + "@angular/compiler": "~8.2.12", + "@angular/compiler-cli": "~8.2.12", + "@angular/core": "~8.2.12", + "@angular/forms": "~8.2.12", + "@angular/language-service": "~8.2.12", + "@angular/platform-browser": "~8.2.12", + "@angular/platform-browser-dynamic": "~8.2.12", + "@angular/router": "~8.2.12", "@fortawesome/fontawesome-free": "^5.11.2", "@ng-bootstrap/ng-bootstrap": "^5.1.0", "@ngneat/spectator": "^4.5.0", diff --git a/npm/ng-packs/packages/theme-shared/package.json b/npm/ng-packs/packages/theme-shared/package.json index 31ccc18ddc..7ffd4ea089 100644 --- a/npm/ng-packs/packages/theme-shared/package.json +++ b/npm/ng-packs/packages/theme-shared/package.json @@ -3,16 +3,16 @@ "version": "1.0.2", "dependencies": { "@abp/ng.core": "^1.0.2", - "@angular/cdk": "^8.0.1", + "@angular/cdk": "^8.2.3", "@fortawesome/fontawesome-free": "^5.11.2", - "@ng-bootstrap/ng-bootstrap": "^5.1.0", + "@ng-bootstrap/ng-bootstrap": "^5.1.2", "@ngx-validate/core": "^0.0.7", "bootstrap": "^4.3.1", "chart.js": "^2.8.0", "font-awesome": "^4.7.0", "ngx-perfect-scrollbar": "^8.0.0", "primeicons": "^2.0.0", - "primeng": "^8.0.4" + "primeng": "^8.1.1" }, "publishConfig": { "access": "public" diff --git a/templates/app/angular/package.json b/templates/app/angular/package.json index 193edadfa7..80eafa7174 100644 --- a/templates/app/angular/package.json +++ b/templates/app/angular/package.json @@ -18,25 +18,25 @@ "@abp/ng.setting-management": "^1.0.2", "@abp/ng.tenant-management": "^1.0.2", "@abp/ng.theme.basic": "^1.0.2", - "@angular/animations": "~8.2.11", - "@angular/common": "~8.2.11", - "@angular/compiler": "~8.2.11", - "@angular/core": "~8.2.11", - "@angular/forms": "~8.2.11", - "@angular/platform-browser": "~8.2.11", - "@angular/platform-browser-dynamic": "~8.2.11", - "@angular/router": "~8.2.11", + "@angular/animations": "~8.2.12", + "@angular/common": "~8.2.12", + "@angular/compiler": "~8.2.12", + "@angular/core": "~8.2.12", + "@angular/forms": "~8.2.12", + "@angular/platform-browser": "~8.2.12", + "@angular/platform-browser-dynamic": "~8.2.12", + "@angular/router": "~8.2.12", "rxjs": "~6.4.0", "tslib": "^1.10.0", "zone.js": "~0.9.1" }, "devDependencies": { - "@angular-devkit/build-angular": "~0.803.12", - "@angular/cli": "~8.3.12", - "@angular/compiler-cli": "~8.2.11", - "@angular/language-service": "~8.2.11", + "@angular-devkit/build-angular": "~0.803.15", + "@angular/cli": "~8.3.15", + "@angular/compiler-cli": "~8.2.12", + "@angular/language-service": "~8.2.12", "@angularclass/hmr": "^2.1.3", - "@ngxs/hmr-plugin": "^3.5.0", + "@ngxs/hmr-plugin": "^3.5.1", "@ngxs/logger-plugin": "^3.5.1", "@types/jasmine": "~3.3.8", "@types/jasminewd2": "~2.0.3",