From 81915742a92e8344375f3a6d6b2bc96ff7a5643e Mon Sep 17 00:00:00 2001 From: rushannanayakkara Date: Tue, 23 Apr 2024 20:55:54 +0530 Subject: [PATCH] Add maxFailedAttemptCount to recovery form and restructure the form. --- .../src/extensions/i18n/models/extensions.ts | 4 +- .../i18n/resources/en-US/extensions.ts | 20 ++- .../governance-connector-constants.ts | 8 ++ .../server-configurations-constants.ts | 4 +- .../forms/password-recovery-form.tsx | 121 ++++++++++++++---- 5 files changed, 129 insertions(+), 28 deletions(-) diff --git a/apps/console/src/extensions/i18n/models/extensions.ts b/apps/console/src/extensions/i18n/models/extensions.ts index ae7e16fa018..89dd5f92bd5 100755 --- a/apps/console/src/extensions/i18n/models/extensions.ts +++ b/apps/console/src/extensions/i18n/models/extensions.ts @@ -3039,7 +3039,8 @@ export interface Extensions { enableEmailBasedRecovery: FormAttributes; expiryTime: FormAttributes; notifySuccess: FormAttributes; - otpMaxResendCount: FormAttributes; + maxResendCount: FormAttributes; + maxFailedAttemptCount: FormAttributes; smsOtpExpiryTime: FormAttributes; passwordRecoveryOtpUseUppercase: FormAttributes; passwordRecoveryOtpUseLowercase: FormAttributes; @@ -3051,6 +3052,7 @@ export interface Extensions { recoveryOptionSubHeadingSMS: string; recoveryOptionHeading: string; otpConfigHeading: string; + otherConfigHeading: string; connectorDescription: string; heading: string; notification: { diff --git a/apps/console/src/extensions/i18n/resources/en-US/extensions.ts b/apps/console/src/extensions/i18n/resources/en-US/extensions.ts index d87e1fd227b..5e02dfb0454 100755 --- a/apps/console/src/extensions/i18n/resources/en-US/extensions.ts +++ b/apps/console/src/extensions/i18n/resources/en-US/extensions.ts @@ -3578,9 +3578,9 @@ export const extensions: Extensions = { "recovery is successful.", label: "Notify on successful recovery" }, - otpMaxResendCount: { - hint: "Password recovery OTP maximum resend count.", - label: "Max resend count", + maxResendCount: { + hint: "Password recovery maximum resend count.", + label: "Max resend attempts count", placeholder: "Enter max resend count", validations: { invalid: "Password recovery OTP resend count should be an integer.", @@ -3591,6 +3591,19 @@ export const extensions: Extensions = { "Password recovery OTP resend count should be a number with 1 digits." } }, + maxFailedAttemptCount: { + hint: "Password recovery maximum failed attempt count.", + label: "Max failed attempts count", + placeholder: "Enter max failed attempts", + validations: { + invalid: "Password recovery max failed attempts count should be an integer.", + empty: "Password recovery max failed attempts count cannot be empty.", + range: + "Password recovery max failed attempts count should be between 1 & 10.", + maxLengthReached: + "Password recovery max failed attempts count should be a number with less than 3 digits." + } + }, smsOtpExpiryTime: { hint: "Password recovery OTP expiry time in minutes.", label: "Password recovery OTP expiry time", @@ -3637,6 +3650,7 @@ export const extensions: Extensions = { recoveryOptionSubHeadingSMS: "SMS OTP", recoveryOptionHeading: "Recovery Option Selection", otpConfigHeading: "OTP Code Configuration", + otherConfigHeading: "Other Configuration", connectorDescription: "Enable self-service password recovery for users " + "on the login page.", heading: "Password Recovery", notification: { diff --git a/features/admin.server-configurations.v1/constants/governance-connector-constants.ts b/features/admin.server-configurations.v1/constants/governance-connector-constants.ts index 3a86b443e93..3df975b24da 100644 --- a/features/admin.server-configurations.v1/constants/governance-connector-constants.ts +++ b/features/admin.server-configurations.v1/constants/governance-connector-constants.ts @@ -60,6 +60,10 @@ export class GovernanceConnectorConstants { EXPIRY_TIME_MAX_VALUE: number; EXPIRY_TIME_MIN_LENGTH: number; EXPIRY_TIME_MIN_VALUE: number; + MAX_FAILED_ATTEMPT_COUNT_MIN_LENGTH: number; + MAX_FAILED_ATTEMPT_COUNT_MAX_LENGTH: number; + MAX_FAILED_ATTEMPT_COUNT_MIN_VALUE: number; + MAX_FAILED_ATTEMPT_COUNT_MAX_VALUE: number; MAX_RESEND_COUNT_MIN_LENGTH: number; MAX_RESEND_COUNT_MAX_LENGTH: number; MAX_RESEND_COUNT_MIN_VALUE: number; @@ -76,6 +80,10 @@ export class GovernanceConnectorConstants { EXPIRY_TIME_MAX_VALUE: 10080, EXPIRY_TIME_MIN_LENGTH: 1, EXPIRY_TIME_MIN_VALUE: 1, + MAX_FAILED_ATTEMPT_COUNT_MAX_LENGTH: 2, + MAX_FAILED_ATTEMPT_COUNT_MAX_VALUE: 10, + MAX_FAILED_ATTEMPT_COUNT_MIN_LENGTH: 1, + MAX_FAILED_ATTEMPT_COUNT_MIN_VALUE: 1, MAX_RESEND_COUNT_MAX_LENGTH: 1, MAX_RESEND_COUNT_MAX_VALUE: 5, MAX_RESEND_COUNT_MIN_LENGTH: 1, diff --git a/features/admin.server-configurations.v1/constants/server-configurations-constants.ts b/features/admin.server-configurations.v1/constants/server-configurations-constants.ts index 65d5b30507a..90967151c73 100644 --- a/features/admin.server-configurations.v1/constants/server-configurations-constants.ts +++ b/features/admin.server-configurations.v1/constants/server-configurations-constants.ts @@ -248,7 +248,9 @@ export class ServerConfigurationsConstants { public static readonly RECOVERY_OTP_USE_NUMERIC: string = "Recovery.Notification.Password.OTP.UseNumbersInOTP"; public static readonly RECOVERY_OTP_LENGTH: string = "Recovery.Notification.Password.OTP.OTPLength"; - public static readonly RECOVERY_OTP_MAX_RESEND_COUNT: string = "Recovery.Notification.Password.MaxResendAttempts"; + public static readonly RECOVERY_MAX_RESEND_COUNT: string = "Recovery.Notification.Password.MaxResendAttempts"; + public static readonly RECOVERY_MAX_FAILED_ATTEMPTS_COUNT: string = + "Recovery.Notification.Password.MaxFailedAttempts"; /** * Login policies - account locking API Keyword constants. diff --git a/features/admin.server-configurations.v1/forms/password-recovery-form.tsx b/features/admin.server-configurations.v1/forms/password-recovery-form.tsx index fa880ee6cc7..738af0dbc0b 100644 --- a/features/admin.server-configurations.v1/forms/password-recovery-form.tsx +++ b/features/admin.server-configurations.v1/forms/password-recovery-form.tsx @@ -100,9 +100,13 @@ interface PasswordRecoveryFormInitialValuesInterface { */ smsOtpLength: string; /** - * The maximum amount of times otp is resent. + * The maximum amount of times recovery code/link is resent. */ - otpMaxResendCount: string; + maxResendCount: string; + /** + * The maximum allowed failed attempts for a recovery flow. + */ + maxFailedAttemptCount: string; } /** @@ -122,9 +126,13 @@ export interface PasswordRecoveryFormErrorValidationsInterface { */ smsOtpLength: string; /** - * OTP max resend count field. + * max resend count field. + */ + maxResendCount: string; + /** + * Max allowed failed attempts count field. */ - otpMaxResendCount: string; + maxFailedAttemptCount: string; } const allowedConnectorFields: string[] = [ @@ -137,7 +145,8 @@ const allowedConnectorFields: string[] = [ ServerConfigurationsConstants.RECOVERY_OTP_USE_LOWERCASE, ServerConfigurationsConstants.RECOVERY_OTP_USE_NUMERIC, ServerConfigurationsConstants.RECOVERY_OTP_LENGTH, - ServerConfigurationsConstants.RECOVERY_OTP_MAX_RESEND_COUNT + ServerConfigurationsConstants.RECOVERY_MAX_RESEND_COUNT, + ServerConfigurationsConstants.RECOVERY_MAX_FAILED_ATTEMPTS_COUNT ]; const FORM_ID: string = "governance-connectors-password-recovery-form"; @@ -228,10 +237,15 @@ export const PasswordRecoveryConfigurationForm: FunctionComponent { const errors: PasswordRecoveryFormErrorValidationsInterface = { expiryTime: undefined, - otpMaxResendCount: undefined, + maxFailedAttemptCount: undefined, + maxResendCount: undefined, smsOtpExpiryTime: undefined, smsOtpLength: undefined }; @@ -312,17 +327,28 @@ export const PasswordRecoveryConfigurationForm: FunctionComponent GovernanceConnectorConstants + parseInt(values.maxResendCount, 10) > GovernanceConnectorConstants .PASSWORD_RECOVERY_FORM_FIELD_CONSTRAINTS.MAX_RESEND_COUNT_MAX_VALUE) { - // Check for invalid input length. - errors.otpMaxResendCount = t("extensions:manage.serverConfigurations.accountRecovery." + - "passwordRecovery.form.fields.otpMaxResendCount.validations.maxLengthReached"); + // Check for invalid range. + errors.maxResendCount = t("extensions:manage.serverConfigurations.accountRecovery." + + "passwordRecovery.form.fields.maxResendCount.validations.range"); + } else if (!values.maxFailedAttemptCount) { + // Check for required error + errors.maxFailedAttemptCount = t("extensions:manage.serverConfigurations.accountRecovery." + + "passwordRecovery.form.fields.maxFailedAttemptCount.validations.empty"); + } else if (parseInt(values.maxFailedAttemptCount, 10) < GovernanceConnectorConstants + .PASSWORD_RECOVERY_FORM_FIELD_CONSTRAINTS.MAX_FAILED_ATTEMPT_COUNT_MIN_VALUE || + parseInt(values.maxFailedAttemptCount, 10) > GovernanceConnectorConstants + .PASSWORD_RECOVERY_FORM_FIELD_CONSTRAINTS.MAX_FAILED_ATTEMPT_COUNT_MAX_VALUE) { + // Check for invalid range. + errors.maxFailedAttemptCount = t("extensions:manage.serverConfigurations.accountRecovery." + + "passwordRecovery.form.fields.maxFailedAttemptCount.validations.range"); } return errors; @@ -339,6 +365,7 @@ export const PasswordRecoveryConfigurationForm: FunctionComponent + + + { t("extensions:manage.serverConfigurations.accountRecovery." + + "passwordRecovery.otherConfigHeading") as ReactNode } + + + + + + { t("extensions:manage.serverConfigurations.accountRecovery." + + "passwordRecovery.form.fields.maxFailedAttemptCount.hint") as ReactNode } + { t("extensions:manage.serverConfigurations.accountRecovery." + - "passwordRecovery.form.fields.otpMaxResendCount.hint") as ReactNode } + "passwordRecovery.form.fields.maxResendCount.hint") as ReactNode }