From 8fdf8fb10c00026c316f48515918ee7f44ba2fa1 Mon Sep 17 00:00:00 2001 From: Jose Alberto Hernandez Date: Mon, 6 May 2024 21:05:16 -0600 Subject: [PATCH] Strongest password policy --- .../chart-of-accounts.component.ts | 6 +- .../create-self-service-user.component.html | 55 ++++++++++++++----- .../create-self-service-user.component.ts | 28 ++-------- .../general-tab/general-tab.component.html | 32 ++++++++--- src/app/core/utils/passwords-utility.ts | 37 +++++++++++++ .../loans-view/loans-view.component.html | 5 +- .../reset-password.component.html | 13 ++++- .../reset-password.component.ts | 6 +- .../organization/offices/offices.component.ts | 6 +- src/app/pipes/pipes.module.ts | 10 +++- src/app/pipes/truncate-text.pipe.ts | 21 +++++++ .../create-tax-component.component.html | 4 +- .../view-tax-component.component.html | 2 +- .../savings-account-view.component.html | 5 +- .../search-page/search-page.component.ts | 3 + .../change-password-dialog.component.ts | 6 +- .../shared/long-text/long-text.component.html | 5 ++ .../shared/long-text/long-text.component.scss | 0 .../long-text/long-text.component.spec.ts | 23 ++++++++ .../shared/long-text/long-text.component.ts | 37 +++++++++++++ src/app/shared/shared.module.ts | 7 ++- .../create-user/create-user.component.html | 11 +++- .../create-user/create-user.component.ts | 16 +++--- src/assets/translations/cs-CS.json | 2 + src/assets/translations/de-DE.json | 2 + src/assets/translations/en-US.json | 2 + src/assets/translations/es-MX.json | 2 + src/assets/translations/fr-FR.json | 2 + src/assets/translations/it-IT.json | 2 + src/assets/translations/ko-KO.json | 2 + src/assets/translations/lt-LT.json | 2 + src/assets/translations/lv-LV.json | 2 + src/assets/translations/ne-NE.json | 2 + src/assets/translations/pt-PT.json | 2 + src/assets/translations/sw-SW.json | 2 + 35 files changed, 283 insertions(+), 79 deletions(-) create mode 100644 src/app/core/utils/passwords-utility.ts create mode 100644 src/app/pipes/truncate-text.pipe.ts create mode 100644 src/app/shared/long-text/long-text.component.html create mode 100644 src/app/shared/long-text/long-text.component.scss create mode 100644 src/app/shared/long-text/long-text.component.spec.ts create mode 100644 src/app/shared/long-text/long-text.component.ts diff --git a/src/app/accounting/chart-of-accounts/chart-of-accounts.component.ts b/src/app/accounting/chart-of-accounts/chart-of-accounts.component.ts index a059512ef..c2f6a624a 100644 --- a/src/app/accounting/chart-of-accounts/chart-of-accounts.component.ts +++ b/src/app/accounting/chart-of-accounts/chart-of-accounts.component.ts @@ -45,7 +45,7 @@ export class ChartOfAccountsComponent implements AfterViewInit, OnInit { /** Selected GL Account. */ glAccount: GLAccountNode; /** Flag to check if tree is expanded or collapsed. */ - isTreeExpanded: boolean = true; + isTreeExpanded = true; /** Paginator for chart of accounts table. */ @ViewChild(MatPaginator, { static: true }) paginator: MatPaginator; @@ -182,9 +182,9 @@ export class ChartOfAccountsComponent implements AfterViewInit, OnInit { this.router.navigate(['/accounting']); } - /** + /** * Expand and Collapse the tree - */ + */ toggleExpandCollapse() { this.isTreeExpanded = this.treeControlService.toggleExpandCollapse(this.nestedTreeControl, this.isTreeExpanded); } diff --git a/src/app/clients/clients-view/client-actions/create-self-service-user/create-self-service-user.component.html b/src/app/clients/clients-view/client-actions/create-self-service-user/create-self-service-user.component.html index 8b7ee776a..001ccd4fe 100644 --- a/src/app/clients/clients-view/client-actions/create-self-service-user/create-self-service-user.component.html +++ b/src/app/clients/clients-view/client-actions/create-self-service-user/create-self-service-user.component.html @@ -12,7 +12,8 @@ {{"labels.inputs.User Name" | translate}} - {{"labels.inputs.User Name" | translate}} {{"labels.commons.is" | translate}} {{"labels.commons.required" | translate}} + {{"labels.inputs.User Name" | translate}} {{"labels.commons.is" | translate}} + {{"labels.commons.required" | translate}} @@ -20,7 +21,8 @@ {{"labels.inputs.First Name" | translate}} - {{"labels.inputs.First Name" | translate}} {{"labels.commons.is" | translate}} {{"labels.commons.required" | translate}} + {{"labels.inputs.First Name" | translate}} {{"labels.commons.is" | translate}} + {{"labels.commons.required" | translate}} @@ -28,7 +30,8 @@ {{"labels.inputs.Last Name" | translate}} - {{"labels.inputs.Last Name" | translate}} {{"labels.commons.is" | translate}} {{"labels.commons.required" | translate}} + {{"labels.inputs.Last Name" | translate}} {{"labels.commons.is" | translate}} + {{"labels.commons.required" | translate}} @@ -36,10 +39,12 @@ {{"labels.inputs.Email" | translate}} - {{"labels.inputs.Email" | translate}} {{"labels.commons.is" | translate}} {{"labels.commons.required" | translate}} + {{"labels.inputs.Email" | translate}} {{"labels.commons.is" | translate}} + {{"labels.commons.required" | translate}} - {{"labels.inputs.Email should be a" | translate}} {{"labels.inputs.valid" | translate}} {{"labels.inputs.email" | translate}}. + {{"labels.inputs.Email should be a" | translate}} {{"labels.inputs.valid" | + translate}} {{"labels.inputs.email" | translate}}. @@ -53,15 +58,30 @@ {{"labels.inputs.Override Password Expire Policy" | translate}} ? - + - {{"labels.inputs.Password" | translate}} - + {{ 'labels.inputs.Password' | translate }} + - {{"labels.inputs.Password" | translate}} {{"labels.commons.is" | translate}} {{"labels.commons.required" | translate}} + {{ 'labels.inputs.Password' | translate }} {{'labels.commons.is required' | translate }} + + + {{'labels.commons.Password should be at least' | translate }} {{'labels.commons.8 characters long' | translate }} + + + {{'labels.commons.Password should not be more than' | translate }} + {{'labels.commons.50 characters long' | translate }} + + + {{'labels.commons.Password should include a' | translate }} + {{'labels.commons.numeral' | translate }} {{'labels.commons.and at' | translate }} + {{'labels.commons.least one uppercase' | translate }} + ,{{'labels.commons.lowercase and special character' | translate }} @@ -69,10 +89,12 @@ {{"labels.inputs.Repeat Password" | translate}} - {{"labels.inputs.Repeat password" | translate}} {{"labels.commons.is" | translate}} {{"labels.commons.required" | translate}} + {{"labels.inputs.Repeat password" | translate}} {{"labels.commons.is" | translate}} + {{"labels.commons.required" | translate}} - {{"labels.inputs.Passwords should be" | translate}} {{"labels.inputs.matched" | translate}} + {{"labels.inputs.Passwords should be" | translate}} {{"labels.inputs.matched" | + translate}} @@ -84,9 +106,12 @@ - - - + + + @@ -95,4 +120,4 @@ - + \ No newline at end of file diff --git a/src/app/clients/clients-view/client-actions/create-self-service-user/create-self-service-user.component.ts b/src/app/clients/clients-view/client-actions/create-self-service-user/create-self-service-user.component.ts index 75bca44d7..58d1c454d 100644 --- a/src/app/clients/clients-view/client-actions/create-self-service-user/create-self-service-user.component.ts +++ b/src/app/clients/clients-view/client-actions/create-self-service-user/create-self-service-user.component.ts @@ -6,6 +6,7 @@ import { Subscription } from 'rxjs'; /** Client Services. */ import { ClientsService } from 'app/clients/clients.service'; +import { PasswordsUtility } from 'app/core/utils/passwords-utility'; @Component({ selector: 'mifosx-create-self-service-user', @@ -21,7 +22,8 @@ export class CreateSelfServiceUserComponent implements OnInit { constructor(private formBuilder: UntypedFormBuilder, private route: ActivatedRoute, private clientService: ClientsService, - private router: Router) { + private router: Router, + private passwordsUtility: PasswordsUtility) { this.route.data.subscribe((data: { clientActionData: any}) => { this.clientData = data.clientActionData; }); @@ -43,8 +45,8 @@ export class CreateSelfServiceUserComponent implements OnInit { this.createSelfServiceForm.removeControl('repeatPassword'); } else { this.hidePasswordField = false; - this.createSelfServiceForm.addControl('password', new UntypedFormControl('', [Validators.required])); - this.createSelfServiceForm.addControl('repeatPassword', new UntypedFormControl('', [Validators.required, this.confirmPassword('password')])); + this.createSelfServiceForm.addControl('password', new UntypedFormControl('', this.passwordsUtility.getPasswordValidators())); + this.createSelfServiceForm.addControl('repeatPassword', new UntypedFormControl('', [Validators.required, this.passwordsUtility.confirmPassword('password')])); } }); } @@ -83,24 +85,4 @@ export class CreateSelfServiceUserComponent implements OnInit { }); } - /** - * Confirm Change Password of Users - * @param controlNameToCompare Form Control Name to be compared. - */ - confirmPassword(controlNameToCompare: string): ValidatorFn { - return (c: AbstractControl): ValidationErrors|null => { - if (c.value == null || c.value.length === 0) { - return null; - } - const controlToCompare = c.root.get(controlNameToCompare); - if (controlToCompare) { - const subscription: Subscription = controlToCompare.valueChanges.subscribe(() => { - c.updateValueAndValidity(); - subscription.unsubscribe(); - }); - } - return controlToCompare && controlToCompare.value !== c.value ? {'notequal': true} : null; - }; - } - } diff --git a/src/app/clients/clients-view/general-tab/general-tab.component.html b/src/app/clients/clients-view/general-tab/general-tab.component.html index 5a9cfa52c..407d9407f 100644 --- a/src/app/clients/clients-view/general-tab/general-tab.component.html +++ b/src/app/clients/clients-view/general-tab/general-tab.component.html @@ -121,7 +121,9 @@ {{"labels.inputs.Loan Product" | translate}} - {{element.productName}} + + + @@ -195,7 +197,9 @@ {{"labels.inputs.Loan Product" | translate}} - {{element.productName}} + + + @@ -260,7 +264,9 @@ {{"labels.inputs.Savings Product" | translate}} - {{element.productName}} + + + @@ -320,7 +326,9 @@ {{"labels.inputs.Saving Product" | translate}} - {{element.productName}} + + + @@ -415,7 +423,9 @@ {{"labels.inputs.Fixed Deposit Product" | translate}} - {{element.productName}} + + + @@ -458,7 +468,9 @@ {{"labels.inputs.Recurring Deposit Product" | translate}} - {{element.productName}} + + + @@ -515,7 +527,9 @@ {{"labels.inputs.Recurring Deposit Product" | translate}} - {{element.productName}} + + + @@ -556,7 +570,9 @@ {{"labels.inputs.Share Product" | translate}} - {{element.productName}} + + + diff --git a/src/app/core/utils/passwords-utility.ts b/src/app/core/utils/passwords-utility.ts new file mode 100644 index 000000000..850a300cc --- /dev/null +++ b/src/app/core/utils/passwords-utility.ts @@ -0,0 +1,37 @@ +import { Injectable } from '@angular/core'; +import { AbstractControl, ValidationErrors, ValidatorFn, Validators } from '@angular/forms'; +import { Subscription } from 'rxjs'; + + +@Injectable({ + providedIn: 'root' +}) + +export class PasswordsUtility { + // password regex pattern + public static PASSWORD_REGEX = '^(?=.*?[A-Z])(?=.*?[a-z])(?=.*?[0-9])(?=.*[#$@$!%*?&])[A-Za-z\d#$@$!%*?&].{8,}$'; + + public getPasswordValidators(): ValidatorFn[] { + return [Validators.required, Validators.pattern(PasswordsUtility.PASSWORD_REGEX), Validators.maxLength(50), Validators.minLength(8)]; + } + + /** + * Confirm Change Password of Users + * @param controlNameToCompare Form Control Name to be compared. + */ + public confirmPassword(controlNameToCompare: string): ValidatorFn { + return (c: AbstractControl): ValidationErrors|null => { + if (c.value == null || c.value.length === 0) { + return null; + } + const controlToCompare = c.root.get(controlNameToCompare); + if (controlToCompare) { + const subscription: Subscription = controlToCompare.valueChanges.subscribe(() => { + c.updateValueAndValidity(); + subscription.unsubscribe(); + }); + } + return controlToCompare && controlToCompare.value !== c.value ? {'notequal': true} : null; + }; + } +} diff --git a/src/app/loans/loans-view/loans-view.component.html b/src/app/loans/loans-view/loans-view.component.html index d4950319b..d0c09b72e 100644 --- a/src/app/loans/loans-view/loans-view.component.html +++ b/src/app/loans/loans-view/loans-view.component.html @@ -20,8 +20,9 @@

- {{'labels.heading.Loan Product' | translate}}: {{loanDetailsData.loanProductName}} - + {{'labels.heading.Loan Product' | translate}} : + +

{{'labels.text.' + entityType | translate}} {{"labels.inputs.name" | translate}} : {{loanDetailsData.clientName || diff --git a/src/app/login/reset-password/reset-password.component.html b/src/app/login/reset-password/reset-password.component.html index b507fb57f..a630bf242 100644 --- a/src/app/login/reset-password/reset-password.component.html +++ b/src/app/login/reset-password/reset-password.component.html @@ -26,8 +26,17 @@ {{'labels.inputs.Confirm Password' | translate}} - - {{'labels.inputs.Confirm Password' | translate}} {{'labels.commons.is required' | translate}} + + {{ 'labels.inputs.Password' | translate }} {{'labels.commons.is required' | translate }} + + + {{'labels.commons.Password should be at least' | translate }} {{'labels.commons.8 characters long' | translate }} + + + {{'labels.commons.Password should not be more than' | translate }} {{'labels.commons.50 characters long' | translate }} + + + {{'labels.commons.Password should include a' | translate }} {{'labels.commons.numeral' | translate }} {{'labels.commons.and at' | translate }} {{'labels.commons.least one uppercase' | translate }} ,{{'labels.commons.lowercase and special character' | translate }} diff --git a/src/app/login/reset-password/reset-password.component.ts b/src/app/login/reset-password/reset-password.component.ts index baaf4b082..fd270bb28 100644 --- a/src/app/login/reset-password/reset-password.component.ts +++ b/src/app/login/reset-password/reset-password.component.ts @@ -10,6 +10,7 @@ import { AuthenticationService } from '../../core/authentication/authentication. /** Custom Validators */ import { confirmPasswordValidator } from './confirm-password.validator'; +import { PasswordsUtility } from 'app/core/utils/passwords-utility'; /** * Reset password component. @@ -33,7 +34,8 @@ export class ResetPasswordComponent implements OnInit { * @param {AuthenticationService} authenticationService Authentication Service. */ constructor(private formBuilder: UntypedFormBuilder, - private authenticationService: AuthenticationService) { } + private authenticationService: AuthenticationService, + private passwordsUtility: PasswordsUtility) { } /** * Creates reset password form. @@ -66,7 +68,7 @@ export class ResetPasswordComponent implements OnInit { */ private createResetPasswordForm() { this.resetPasswordForm = this.formBuilder.group({ - 'password': ['', Validators.required], + 'password': ['', this.passwordsUtility.getPasswordValidators()], 'repeatPassword': ['', Validators.required] }, { validator: confirmPasswordValidator }); } diff --git a/src/app/organization/offices/offices.component.ts b/src/app/organization/offices/offices.component.ts index 4932eff77..2b78a7689 100644 --- a/src/app/organization/offices/offices.component.ts +++ b/src/app/organization/offices/offices.component.ts @@ -45,7 +45,7 @@ export class OfficesComponent implements OnInit, AfterViewInit { /** Office data tables. */ dataTablesData: any; /** Flag to check if tree is expanded or collapsed. */ - isTreeExpanded: boolean = true; + isTreeExpanded = true; /** Paginator for offices table. */ @ViewChild(MatPaginator, { static: true }) paginator: MatPaginator; @@ -190,9 +190,9 @@ export class OfficesComponent implements OnInit, AfterViewInit { this.router.navigate(['/organization']); } - /** + /** * Expand and Collapse the tree - */ + */ toggleExpandCollapse() { this.isTreeExpanded = this.treeControlService.toggleExpandCollapse(this.nestedTreeControl, this.isTreeExpanded); } diff --git a/src/app/pipes/pipes.module.ts b/src/app/pipes/pipes.module.ts index f7818c29c..665e4700e 100644 --- a/src/app/pipes/pipes.module.ts +++ b/src/app/pipes/pipes.module.ts @@ -13,6 +13,7 @@ import { FormatNumberPipe } from './format-number.pipe'; import { YesnoPipe } from './yesno.pipe'; import { PrettyPrintPipe } from './pretty-print.pipe'; import { TranslateCatalogPipe } from './translate-catalog.pipe'; +import { TruncateTextPipe } from './truncate-text.pipe'; @NgModule({ imports: [ @@ -30,7 +31,8 @@ import { TranslateCatalogPipe } from './translate-catalog.pipe'; FormatNumberPipe, YesnoPipe, PrettyPrintPipe, - TranslateCatalogPipe], + TranslateCatalogPipe, + TruncateTextPipe], providers: [StatusLookupPipe, AccountsFilterPipe, ChargesFilterPipe, @@ -43,7 +45,8 @@ import { TranslateCatalogPipe } from './translate-catalog.pipe'; FormatNumberPipe, YesnoPipe, PrettyPrintPipe, - TranslateCatalogPipe], + TranslateCatalogPipe, + TruncateTextPipe], exports: [StatusLookupPipe, AccountsFilterPipe, ChargesFilterPipe, @@ -56,6 +59,7 @@ import { TranslateCatalogPipe } from './translate-catalog.pipe'; FormatNumberPipe, YesnoPipe, PrettyPrintPipe, - TranslateCatalogPipe] + TranslateCatalogPipe, + TruncateTextPipe] }) export class PipesModule { } diff --git a/src/app/pipes/truncate-text.pipe.ts b/src/app/pipes/truncate-text.pipe.ts new file mode 100644 index 000000000..590534dc4 --- /dev/null +++ b/src/app/pipes/truncate-text.pipe.ts @@ -0,0 +1,21 @@ +import { Pipe, PipeTransform } from '@angular/core'; + +@Pipe({ + name: 'truncateText' +}) +export class TruncateTextPipe implements PipeTransform { + + transform(value: string, chars: number): string { + if (value.length <= 40) { + return value; + } + + let truncatedText = value.substring(0, 30); + if (chars) { + truncatedText = value.substring(0, chars); + } + + return truncatedText; + } + +} diff --git a/src/app/products/manage-tax-components/create-tax-component/create-tax-component.component.html b/src/app/products/manage-tax-components/create-tax-component/create-tax-component.component.html index 07b635c36..81097d8b1 100644 --- a/src/app/products/manage-tax-components/create-tax-component/create-tax-component.component.html +++ b/src/app/products/manage-tax-components/create-tax-component/create-tax-component.component.html @@ -34,7 +34,7 @@ {{'labels.inputs.Debit Account Type' | translate}} - {{ 'labels.inputs.accounting.' + debitAccountType.value | translate }} + {{ debitAccountType.value | translateCatalog }} @@ -48,7 +48,7 @@ {{'labels.inputs.Credit Account Type' | translate}} - {{ 'labels.inputs.accounting.' + creditAccountType.value | translate }} + {{ creditAccountType.value | translateCatalog }} diff --git a/src/app/products/manage-tax-components/view-tax-component/view-tax-component.component.html b/src/app/products/manage-tax-components/view-tax-component/view-tax-component.component.html index a07d06e91..8c304ee76 100644 --- a/src/app/products/manage-tax-components/view-tax-component/view-tax-component.component.html +++ b/src/app/products/manage-tax-components/view-tax-component/view-tax-component.component.html @@ -50,7 +50,7 @@
- {{ 'labels.inputs.accounting.' + taxComponentData.creditAccountType.value | translate }} + {{ taxComponentData.creditAccountType.value | translateCatalog }}
diff --git a/src/app/savings/savings-account-view/savings-account-view.component.html b/src/app/savings/savings-account-view/savings-account-view.component.html index b4f997636..f9b336c7b 100644 --- a/src/app/savings/savings-account-view/savings-account-view.component.html +++ b/src/app/savings/savings-account-view/savings-account-view.component.html @@ -19,8 +19,9 @@ [matTooltip]="savingsAccountData.status.value" *ngIf="!savingsAccountData.subStatus.block"> - {{'labels.inputs.Savings Product' | translate}} : {{savingsAccountData.savingsProductName}} - + {{'labels.inputs.Savings Product' | translate}} : + +