diff --git a/frontend/src/app/account/_validators/invalid-password.validator.ts b/frontend/src/app/account/_validators/invalid-password.validator.ts index dc2a686f6a..a18d7d9cb4 100644 --- a/frontend/src/app/account/_validators/invalid-password.validator.ts +++ b/frontend/src/app/account/_validators/invalid-password.validator.ts @@ -6,7 +6,8 @@ export const PASSWORD_INVALID = 'passwordInvalid'; export function invalidPasswordValidator(): ValidatorFn { return (control: AbstractControl): ValidationErrors | null => { - const weak = !PASSWORD_REGEX.test(control.value); + const password = control.value; + const weak = password && !PASSWORD_REGEX.test(password); return weak ? { [PASSWORD_INVALID]: true } : null; }; } diff --git a/frontend/src/app/account/_validators/lowercase-password.ts b/frontend/src/app/account/_validators/lowercase-password.ts new file mode 100644 index 0000000000..a515546898 --- /dev/null +++ b/frontend/src/app/account/_validators/lowercase-password.ts @@ -0,0 +1,12 @@ +import { AbstractControl, ValidationErrors, ValidatorFn } from '@angular/forms'; + +export const LOWERCASE_PASSWORD_REGEX = /^(?=.*[a-z])/; + +export const PASSWORD_LOWERCASE = 'passwordLowercase'; + +export function lowercasePasswordValidator(): ValidatorFn { + return (control: AbstractControl): ValidationErrors | null => { + const missingLowercase = !LOWERCASE_PASSWORD_REGEX.test(control.value); + return missingLowercase ? { [PASSWORD_LOWERCASE]: true } : null; + }; +} diff --git a/frontend/src/app/account/_validators/numeric-password.ts b/frontend/src/app/account/_validators/numeric-password.ts new file mode 100644 index 0000000000..8e4b338af9 --- /dev/null +++ b/frontend/src/app/account/_validators/numeric-password.ts @@ -0,0 +1,12 @@ +import { AbstractControl, ValidationErrors, ValidatorFn } from '@angular/forms'; + +export const NUMERIC_PASSWORD_REGEX = /^(?=.*[0-9])/; + +export const PASSWORD_NUMERIC = 'passwordNumeric'; + +export function numericPasswordValidator(): ValidatorFn { + return (control: AbstractControl): ValidationErrors | null => { + const missingNumeric = !NUMERIC_PASSWORD_REGEX.test(control.value); + return missingNumeric ? { [PASSWORD_NUMERIC]: true } : null; + }; +} diff --git a/frontend/src/app/account/_validators/short-password.ts b/frontend/src/app/account/_validators/short-password.ts new file mode 100644 index 0000000000..015817837d --- /dev/null +++ b/frontend/src/app/account/_validators/short-password.ts @@ -0,0 +1,12 @@ +import { AbstractControl, ValidationErrors, ValidatorFn } from '@angular/forms'; + +export const SHORT_PASSWORD_REGEX = /^(?=.{8,})/; + +export const PASSWORD_SHORT = 'passwordShort'; + +export function shortPasswordValidator(): ValidatorFn { + return (control: AbstractControl): ValidationErrors | null => { + const short = !SHORT_PASSWORD_REGEX.test(control.value); + return short ? { [PASSWORD_SHORT]: true } : null; + }; +} diff --git a/frontend/src/app/account/_validators/special-password.ts b/frontend/src/app/account/_validators/special-password.ts new file mode 100644 index 0000000000..e79fc6200a --- /dev/null +++ b/frontend/src/app/account/_validators/special-password.ts @@ -0,0 +1,12 @@ +import { AbstractControl, ValidationErrors, ValidatorFn } from '@angular/forms'; + +export const SPECIAL_PASSWORD_REGEX = /^(?=.*[!"#$%&'()*+,-.:;<=>?@\\/\\[\]^_`{|}~])/; + +export const PASSWORD_SPECIAL = 'passwordSpecial'; + +export function specialPasswordValidator(): ValidatorFn { + return (control: AbstractControl): ValidationErrors | null => { + const missingSpecial = !SPECIAL_PASSWORD_REGEX.test(control.value); + return missingSpecial ? { [PASSWORD_SPECIAL]: true } : null; + }; +} diff --git a/frontend/src/app/account/_validators/uppercase-password.ts b/frontend/src/app/account/_validators/uppercase-password.ts new file mode 100644 index 0000000000..f80a38a004 --- /dev/null +++ b/frontend/src/app/account/_validators/uppercase-password.ts @@ -0,0 +1,12 @@ +import { AbstractControl, ValidationErrors, ValidatorFn } from '@angular/forms'; + +export const UPPERCASE_PASSWORD_REGEX = /^(?=.*[A-Z])/; + +export const PASSWORD_UPPERCASE = 'passwordUppercase'; + +export function uppercasePasswordValidator(): ValidatorFn { + return (control: AbstractControl): ValidationErrors | null => { + const missingUppercase = !UPPERCASE_PASSWORD_REGEX.test(control.value); + return missingUppercase ? { [PASSWORD_UPPERCASE]: true } : null; + }; +} diff --git a/frontend/src/app/account/_validators/weak-password.validator.ts b/frontend/src/app/account/_validators/weak-password.validator.ts index 8b5fd0847b..712f538131 100644 --- a/frontend/src/app/account/_validators/weak-password.validator.ts +++ b/frontend/src/app/account/_validators/weak-password.validator.ts @@ -1,13 +1,21 @@ import { AbstractControl, ValidationErrors, ValidatorFn } from '@angular/forms'; - -export const STRONG_PASSWORD_REGEX = - /^(?=.*[a-z])(?=.*[A-Z])(?=.*[0-9])(?=.{8,})(?=.*[!"#$%&'()*+,-.:;<=>?@\\/\\[\]^_`{|}~])/; +import { LOWERCASE_PASSWORD_REGEX } from './lowercase-password'; +import { UPPERCASE_PASSWORD_REGEX } from './uppercase-password'; +import { NUMERIC_PASSWORD_REGEX } from './numeric-password'; +import { SPECIAL_PASSWORD_REGEX } from './special-password'; +import { SHORT_PASSWORD_REGEX } from './short-password'; export const PASSWORD_WEAK = 'passwordWeak'; export function weakPasswordValidator(): ValidatorFn { return (control: AbstractControl): ValidationErrors | null => { - const weak = !STRONG_PASSWORD_REGEX.test(control.value); + const weak = !( + LOWERCASE_PASSWORD_REGEX.test(control.value) && + UPPERCASE_PASSWORD_REGEX.test(control.value) && + NUMERIC_PASSWORD_REGEX.test(control.value) && + SPECIAL_PASSWORD_REGEX.test(control.value) && + SHORT_PASSWORD_REGEX.test(control.value) + ); return weak ? { [PASSWORD_WEAK]: true } : null; }; } diff --git a/frontend/src/app/account/account.component.css b/frontend/src/app/account/account.component.css index 516b236f7b..fd7126aadc 100644 --- a/frontend/src/app/account/account.component.css +++ b/frontend/src/app/account/account.component.css @@ -1,3 +1,13 @@ +.layout-container { + display: flex; + flex-direction: column; + min-height: calc(100vh - 80px); + width: 100%; + justify-content: center; + align-items: center; + padding: 1rem; +} + .container { padding: 2rem; background-color: var(--surface-section); diff --git a/frontend/src/app/account/layout.component.html b/frontend/src/app/account/layout.component.html index 0036e0a2f0..0fb48cd93b 100644 --- a/frontend/src/app/account/layout.component.html +++ b/frontend/src/app/account/layout.component.html @@ -1,4 +1,3 @@ -