Browse Source

Merge pull request #2041 from abpframework/feat/dynamic-password-validation

Feat/dynamic password validation
pull/2044/head
Yasin Aydın 7 years ago
committed by GitHub
parent
commit
c32280fc51
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
  1. 30
      npm/ng-packs/package.json
  2. 6
      npm/ng-packs/packages/account/src/lib/components/change-password/change-password.component.ts
  3. 37
      npm/ng-packs/packages/account/src/lib/components/register/register.component.ts
  4. 2
      npm/ng-packs/packages/identity/src/lib/components/users/users.component.html
  5. 44
      npm/ng-packs/packages/identity/src/lib/components/users/users.component.ts
  6. 6
      npm/ng-packs/packages/theme-shared/package.json
  7. 26
      templates/app/angular/package.json

30
npm/ng-packs/package.json

@ -5,7 +5,7 @@
"test": "ng test", "test": "ng test",
"symlink": "symlink", "symlink": "symlink",
"abpng": "abpng", "abpng": "abpng",
"commit": "git-cz && node scripts/push.js", "commit": "git-cz",
"lint": "ng lint --fix", "lint": "ng lint --fix",
"scripts:build": "cd scripts && npm install && npm run build" "scripts:build": "cd scripts && npm install && npm run build"
}, },
@ -19,20 +19,20 @@
"@abp/ng.tenant-management.config": "^1.0.2", "@abp/ng.tenant-management.config": "^1.0.2",
"@abp/ng.theme.shared": "^1.0.2", "@abp/ng.theme.shared": "^1.0.2",
"@angular-builders/jest": "^8.2.0", "@angular-builders/jest": "^8.2.0",
"@angular-devkit/build-angular": "~0.803.6", "@angular-devkit/build-angular": "~0.803.15",
"@angular-devkit/build-ng-packagr": "~0.803.6", "@angular-devkit/build-ng-packagr": "~0.803.15",
"@angular/animations": "~8.2.8", "@angular/animations": "~8.2.12",
"@angular/cdk": "^8.0.1", "@angular/cdk": "^8.2.3",
"@angular/cli": "~8.3.6", "@angular/cli": "~8.3.15",
"@angular/common": "~8.1.2", "@angular/common": "~8.2.12",
"@angular/compiler": "~8.2.8", "@angular/compiler": "~8.2.12",
"@angular/compiler-cli": "~8.2.8", "@angular/compiler-cli": "~8.2.12",
"@angular/core": "~8.1.2", "@angular/core": "~8.2.12",
"@angular/forms": "~8.1.2", "@angular/forms": "~8.2.12",
"@angular/language-service": "~8.2.8", "@angular/language-service": "~8.2.12",
"@angular/platform-browser": "~8.2.8", "@angular/platform-browser": "~8.2.12",
"@angular/platform-browser-dynamic": "~8.2.8", "@angular/platform-browser-dynamic": "~8.2.12",
"@angular/router": "~8.1.2", "@angular/router": "~8.2.12",
"@fortawesome/fontawesome-free": "^5.11.2", "@fortawesome/fontawesome-free": "^5.11.2",
"@ng-bootstrap/ng-bootstrap": "^5.1.0", "@ng-bootstrap/ng-bootstrap": "^5.1.0",
"@ngneat/spectator": "^4.5.0", "@ngneat/spectator": "^4.5.0",

6
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 snq from 'snq';
import { finalize } from 'rxjs/operators'; import { finalize } from 'rxjs/operators';
const { minLength, required } = Validators; const { minLength, required, maxLength } = Validators;
const PASSWORD_FIELDS = ['newPassword', 'repeatNewPassword']; const PASSWORD_FIELDS = ['newPassword', 'repeatNewPassword'];
@ -61,12 +61,12 @@ export class ChangePasswordComponent implements OnInit {
newPassword: [ newPassword: [
'', '',
{ {
validators: [required, validatePassword(passwordRulesArr), minLength(requiredLength)], validators: [required, validatePassword(passwordRulesArr), minLength(requiredLength), maxLength(32)],
}, },
], ],
repeatNewPassword: [ repeatNewPassword: [
'', '',
{ validators: [required, validatePassword(passwordRulesArr), minLength(requiredLength)] }, { validators: [required, validatePassword(passwordRulesArr), minLength(requiredLength), maxLength(32)] },
], ],
}, },
{ {

37
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 { 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 { FormBuilder, FormGroup, Validators } from '@angular/forms';
import { Navigate } from '@ngxs/router-plugin'; import { Navigate } from '@ngxs/router-plugin';
import { Store } from '@ngxs/store'; import { Store } from '@ngxs/store';
@ -10,13 +10,14 @@ import { catchError, finalize, switchMap, take, tap } from 'rxjs/operators';
import snq from 'snq'; import snq from 'snq';
import { RegisterRequest } from '../../models'; import { RegisterRequest } from '../../models';
import { AccountService } from '../../services/account.service'; import { AccountService } from '../../services/account.service';
import { PasswordRules, validatePassword } from '@ngx-validate/core';
const { maxLength, minLength, required, email } = Validators; const { maxLength, minLength, required, email } = Validators;
@Component({ @Component({
selector: 'abp-register', selector: 'abp-register',
templateUrl: './register.component.html', templateUrl: './register.component.html',
}) })
export class RegisterComponent { export class RegisterComponent implements OnInit {
form: FormGroup; form: FormGroup;
inProgress: boolean; inProgress: boolean;
@ -30,10 +31,38 @@ export class RegisterComponent {
) { ) {
this.oauthService.configure(this.store.selectSnapshot(ConfigState.getOne('environment')).oAuthConfig); this.oauthService.configure(this.store.selectSnapshot(ConfigState.getOne('environment')).oAuthConfig);
this.oauthService.loadDiscoveryDocument(); this.oauthService.loadDiscoveryDocument();
}
ngOnInit() {
const passwordRules: ABP.Dictionary<string> = 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({ this.form = this.fb.group({
username: ['', [required, maxLength(255)]], username: ['', [required, maxLength(255)]],
password: ['', [required, maxLength(32)]], password: ['', [required, validatePassword(passwordRulesArr), minLength(requiredLength), maxLength(32)]],
email: ['', [required, email]], email: ['', [required, email]],
}); });
} }

2
npm/ng-packs/packages/identity/src/lib/components/users/users.component.html

@ -115,7 +115,7 @@
</div> </div>
</div> </div>
<abp-modal [(visible)]="isModalVisible" [busy]="modalBusy"> <abp-modal [(visible)]="isModalVisible" [busy]="modalBusy" (disappear)="form = null">
<ng-template #abpHeader> <ng-template #abpHeader>
<h3>{{ (selected?.id ? 'AbpIdentity::Edit' : 'AbpIdentity::NewUser') | abpLocalization }}</h3> <h3>{{ (selected?.id ? 'AbpIdentity::Edit' : 'AbpIdentity::NewUser') | abpLocalization }}</h3>
</ng-template> </ng-template>

44
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 { ConfirmationService, Toaster } from '@abp/ng.theme.shared';
import { Component, TemplateRef, TrackByFunction, ViewChild, OnInit } from '@angular/core'; import { Component, TemplateRef, TrackByFunction, ViewChild, OnInit } from '@angular/core';
import { AbstractControl, FormArray, FormBuilder, FormGroup, Validators, FormControl } from '@angular/forms'; import { AbstractControl, FormArray, FormBuilder, FormGroup, Validators, FormControl } from '@angular/forms';
@ -17,6 +17,7 @@ import {
} from '../../actions/identity.actions'; } from '../../actions/identity.actions';
import { Identity } from '../../models/identity'; import { Identity } from '../../models/identity';
import { IdentityState } from '../../states/identity.state'; import { IdentityState } from '../../states/identity.state';
import { PasswordRules, validatePassword } from '@ngx-validate/core';
@Component({ @Component({
selector: 'abp-users', selector: 'abp-users',
templateUrl: './users.component.html', templateUrl: './users.component.html',
@ -55,6 +56,10 @@ export class UsersComponent implements OnInit {
sortKey = ''; sortKey = '';
passwordRulesArr = [] as PasswordRules;
requiredPasswordLength = 1;
trackByFn: TrackByFunction<AbstractControl> = (index, item) => Object.keys(item)[0] || index; trackByFn: TrackByFunction<AbstractControl> = (index, item) => Object.keys(item)[0] || index;
get roleGroups(): FormGroup[] { get roleGroups(): FormGroup[] {
@ -65,6 +70,30 @@ export class UsersComponent implements OnInit {
ngOnInit() { ngOnInit() {
this.get(); this.get();
const passwordRules: ABP.Dictionary<string> = 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) { 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) { if (!this.selected.userName) {
this.form.addControl('password', new FormControl('', [Validators.required, Validators.maxLength(32)])); this.form.get('password').setValidators([...passwordValidators, Validators.required]);
} else { this.form.get('password').updateValueAndValidity();
this.form.addControl('password', new FormControl('', [Validators.maxLength(32)]));
} }
}); });
} }

6
npm/ng-packs/packages/theme-shared/package.json

@ -3,16 +3,16 @@
"version": "1.0.2", "version": "1.0.2",
"dependencies": { "dependencies": {
"@abp/ng.core": "^1.0.2", "@abp/ng.core": "^1.0.2",
"@angular/cdk": "^8.0.1", "@angular/cdk": "^8.2.3",
"@fortawesome/fontawesome-free": "^5.11.2", "@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", "@ngx-validate/core": "^0.0.7",
"bootstrap": "^4.3.1", "bootstrap": "^4.3.1",
"chart.js": "^2.8.0", "chart.js": "^2.8.0",
"font-awesome": "^4.7.0", "font-awesome": "^4.7.0",
"ngx-perfect-scrollbar": "^8.0.0", "ngx-perfect-scrollbar": "^8.0.0",
"primeicons": "^2.0.0", "primeicons": "^2.0.0",
"primeng": "^8.0.4" "primeng": "^8.1.1"
}, },
"publishConfig": { "publishConfig": {
"access": "public" "access": "public"

26
templates/app/angular/package.json

@ -18,25 +18,25 @@
"@abp/ng.setting-management": "^1.0.2", "@abp/ng.setting-management": "^1.0.2",
"@abp/ng.tenant-management": "^1.0.2", "@abp/ng.tenant-management": "^1.0.2",
"@abp/ng.theme.basic": "^1.0.2", "@abp/ng.theme.basic": "^1.0.2",
"@angular/animations": "~8.2.11", "@angular/animations": "~8.2.12",
"@angular/common": "~8.2.11", "@angular/common": "~8.2.12",
"@angular/compiler": "~8.2.11", "@angular/compiler": "~8.2.12",
"@angular/core": "~8.2.11", "@angular/core": "~8.2.12",
"@angular/forms": "~8.2.11", "@angular/forms": "~8.2.12",
"@angular/platform-browser": "~8.2.11", "@angular/platform-browser": "~8.2.12",
"@angular/platform-browser-dynamic": "~8.2.11", "@angular/platform-browser-dynamic": "~8.2.12",
"@angular/router": "~8.2.11", "@angular/router": "~8.2.12",
"rxjs": "~6.4.0", "rxjs": "~6.4.0",
"tslib": "^1.10.0", "tslib": "^1.10.0",
"zone.js": "~0.9.1" "zone.js": "~0.9.1"
}, },
"devDependencies": { "devDependencies": {
"@angular-devkit/build-angular": "~0.803.12", "@angular-devkit/build-angular": "~0.803.15",
"@angular/cli": "~8.3.12", "@angular/cli": "~8.3.15",
"@angular/compiler-cli": "~8.2.11", "@angular/compiler-cli": "~8.2.12",
"@angular/language-service": "~8.2.11", "@angular/language-service": "~8.2.12",
"@angularclass/hmr": "^2.1.3", "@angularclass/hmr": "^2.1.3",
"@ngxs/hmr-plugin": "^3.5.0", "@ngxs/hmr-plugin": "^3.5.1",
"@ngxs/logger-plugin": "^3.5.1", "@ngxs/logger-plugin": "^3.5.1",
"@types/jasmine": "~3.3.8", "@types/jasmine": "~3.3.8",
"@types/jasminewd2": "~2.0.3", "@types/jasminewd2": "~2.0.3",

Loading…
Cancel
Save