From afb038b057e5725d20351479056dfab346500420 Mon Sep 17 00:00:00 2001 From: Thomas Zemp Date: Thu, 9 Jan 2025 13:19:39 +0100 Subject: [PATCH] fix: use password regex --- i18n/en.pot | 17 ++++++++++------ src/components/UserForm/SecuritySection.js | 20 +++++++++++++++---- .../ContextMenu/Modals/ReplicateModal.js | 14 ++++++++++--- src/providers/system/SystemProvider.js | 7 ++++++- 4 files changed, 44 insertions(+), 14 deletions(-) diff --git a/i18n/en.pot b/i18n/en.pot index 42c95169..1f52e58b 100644 --- a/i18n/en.pot +++ b/i18n/en.pot @@ -5,8 +5,8 @@ msgstr "" "Content-Type: text/plain; charset=utf-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1)\n" -"POT-Creation-Date: 2024-12-18T07:54:11.061Z\n" -"PO-Revision-Date: 2024-12-18T07:54:11.062Z\n" +"POT-Creation-Date: 2025-01-09T12:18:17.999Z\n" +"PO-Revision-Date: 2025-01-09T12:18:17.999Z\n" msgid "Yes" msgstr "Yes" @@ -603,6 +603,9 @@ msgstr "You do not have permission to assign certain user roles" msgid "User groups this user is a member of" msgstr "User groups this user is a member of" +msgid "Invalid password" +msgstr "Invalid password" + msgid "Security" msgstr "Security" @@ -619,11 +622,13 @@ msgid "Password" msgstr "Password" msgid "" -"Password should be at least 8 characters long, with at least one lowercase " -"character, one uppercase character and one special character." +"Password should be between {{minPasswordLength}} and {{maxPasswordLength}} " +"characters long, with at least one lowercase character, one uppercase " +"character, one number, and one special character." msgstr "" -"Password should be at least 8 characters long, with at least one lowercase " -"character, one uppercase character and one special character." +"Password should be between {{minPasswordLength}} and {{maxPasswordLength}} " +"characters long, with at least one lowercase character, one uppercase " +"character, one number, and one special character." msgid "Repeat new password" msgstr "Repeat new password" diff --git a/src/components/UserForm/SecuritySection.js b/src/components/UserForm/SecuritySection.js index 5bc51e57..3f576cbe 100644 --- a/src/components/UserForm/SecuritySection.js +++ b/src/components/UserForm/SecuritySection.js @@ -1,8 +1,9 @@ import i18n from '@dhis2/d2-i18n' -import { composeValidators, hasValue, dhis2Password } from '@dhis2/ui' +import { composeValidators, hasValue, createPattern } from '@dhis2/ui' import moment from 'moment' import PropTypes from 'prop-types' import React from 'react' +import { useSystemInformation } from '../../providers/index.js' import { FormSection, CheckboxField, @@ -15,6 +16,16 @@ import { createRepeatPasswordValidator } from './validators.js' const SecuritySection = React.memo( ({ user, inviteUser, externalAuth, changePassword, password }) => { + const { + minPasswordLength, + maxPasswordLength, + passwordValidationPattern, + } = useSystemInformation() + const passwordRegex = new RegExp(passwordValidationPattern) + const passwordRegExValidator = createPattern( + passwordRegex, + i18n.t('Invalid password') + ) if (inviteUser === 'INVITE_USER') { return null } @@ -48,16 +59,17 @@ const SecuritySection = React.memo( : i18n.t('Password') } helpText={i18n.t( - 'Password should be at least 8 characters long, with at least one lowercase character, one uppercase character and one special character.' + 'Password should be between {{minPasswordLength}} and {{maxPasswordLength}} characters long, with at least one lowercase character, one uppercase character, one number, and one special character.', + { minPasswordLength, maxPasswordLength } )} initialValue="" autoComplete="new-password" validate={ user && !changePassword - ? dhis2Password + ? passwordRegExValidator : composeValidators( hasValue, - dhis2Password + passwordRegExValidator ) } /> diff --git a/src/pages/UserList/ContextMenu/Modals/ReplicateModal.js b/src/pages/UserList/ContextMenu/Modals/ReplicateModal.js index 92f768df..8f51cc60 100644 --- a/src/pages/UserList/ContextMenu/Modals/ReplicateModal.js +++ b/src/pages/UserList/ContextMenu/Modals/ReplicateModal.js @@ -9,7 +9,7 @@ import { Button, ReactFinalForm, InputFieldFF, - dhis2Password, + createPattern, composeValidators, hasValue, } from '@dhis2/ui' @@ -18,6 +18,7 @@ import React from 'react' import { TextField } from '../../../../components/Form.js' import { useUserNameValidator } from '../../../../components/UserForm/validators.js' import { useFetchAlert } from '../../../../hooks/useFetchAlert.js' +import { useSystemInformation } from '../../../../providers/index.js' import styles from './ReplicateModal.module.css' const ReplicateModal = ({ user, refetchUsers, onClose }) => { @@ -27,6 +28,9 @@ const ReplicateModal = ({ user, refetchUsers, onClose }) => { isInviteUser: false, }) const { showSuccess, showError } = useFetchAlert() + const { minPasswordLength, maxPasswordLength, passwordValidationPattern } = + useSystemInformation() + const passwordRegex = new RegExp(passwordValidationPattern) const handleReplicate = async ({ username, password }) => { try { @@ -79,11 +83,15 @@ const ReplicateModal = ({ user, refetchUsers, onClose }) => { type="password" placeholder={i18n.t('Password for new user')} helpText={i18n.t( - 'Password should be at least 8 characters long, with at least one lowercase character, one uppercase character and one special character.' + 'Password should be between {{minPasswordLength}} and {{maxPasswordLength}} characters long, with at least one lowercase character, one uppercase character, one number, and one special character.', + { minPasswordLength, maxPasswordLength } )} validate={composeValidators( hasValue, - dhis2Password + createPattern( + passwordRegex, + i18n.t('Invalid password') + ) )} autoComplete="new-password" className={styles.field} diff --git a/src/providers/system/SystemProvider.js b/src/providers/system/SystemProvider.js index 351046ef..de8c7fb7 100644 --- a/src/providers/system/SystemProvider.js +++ b/src/providers/system/SystemProvider.js @@ -10,7 +10,7 @@ const query = { resource: '/authorities', }, systemSettings: { - resource: '/systemSettings/keyCanGrantOwnUserAuthorityGroups', + resource: '/systemSettings', }, } @@ -53,6 +53,11 @@ export const SystemProvider = ({ children }) => { usersCanAssignOwnUserRoles: Boolean( data.systemSettings?.keyCanGrantOwnUserAuthorityGroups ), + minPasswordLength: Number(data.systemSettings?.minPasswordLength), + maxPasswordLength: Number(data.systemSettings?.maxPasswordLength), + passwordValidationPattern: + data.systemSettings?.passwordValidationPattern ?? + '^(?=.*[A-Z])(?=.*\\d)(?=.*[\\W_])[A-Za-z\\d\\W_]{8,32}$', } return (