From cd612f4c77728aa0854ad807638081bf18bc8659 Mon Sep 17 00:00:00 2001 From: Sylvain Date: Mon, 13 Mar 2023 11:10:36 +0100 Subject: [PATCH] (bug) URL validation regex was wrong --- .../authentication-provider/oauth2-form.tsx | 13 +++++-------- .../openid-connect-form.tsx | 19 ++++++++----------- .../editorial-block/editorial-block-form.tsx | 6 ++---- .../components/socials/edit-socials.tsx | 5 ++--- .../components/socials/fab-socials.tsx | 5 ++--- .../components/user/user-profile-form.tsx | 9 +++------ app/frontend/src/javascript/lib/validation.ts | 6 ++++++ 7 files changed, 28 insertions(+), 35 deletions(-) create mode 100644 app/frontend/src/javascript/lib/validation.ts diff --git a/app/frontend/src/javascript/components/authentication-provider/oauth2-form.tsx b/app/frontend/src/javascript/components/authentication-provider/oauth2-form.tsx index bc19f5302..fcf587454 100644 --- a/app/frontend/src/javascript/components/authentication-provider/oauth2-form.tsx +++ b/app/frontend/src/javascript/components/authentication-provider/oauth2-form.tsx @@ -3,6 +3,7 @@ import { UseFormRegister, FormState } from 'react-hook-form'; import { FieldValues } from 'react-hook-form/dist/types/fields'; import { useTranslation } from 'react-i18next'; import { FabOutputCopy } from '../base/fab-output-copy'; +import ValidationLib from '../../lib/validation'; interface Oauth2FormProps { register: UseFormRegister, @@ -16,10 +17,6 @@ interface Oauth2FormProps { export const Oauth2Form = ({ register, strategyName, formState }: Oauth2FormProps) => { const { t } = useTranslation('admin'); - // regular expression to validate the input fields - const endpointRegex = /^\/?([-._~:?#[\]@!$&'()*+,;=%\w]+\/?)*$/; - const urlRegex = /^(https?:\/\/)([^.]+)\.(.{2,30})(\/.*)*\/?$/; - /** * Build the callback URL, based on the strategy name. */ @@ -35,26 +32,26 @@ export const Oauth2Form = ({ register, strateg register={register} placeholder="https://sso.example.net..." label={t('app.admin.authentication.oauth2_form.common_url')} - rules={{ required: true, pattern: urlRegex }} + rules={{ required: true, pattern: ValidationLib.urlRegex }} formState={formState} /> { register: UseFormRegister, @@ -51,10 +52,6 @@ export const OpenidConnectForm = ); }, []); - // regular expression to validate the input fields - const endpointRegex = /^\/?([-._~:?#[\]@!$&'()*+,;=%\w]+\/?)*$/; - const urlRegex = /^(https?:\/\/)([^.]+)\.(.{2,30})(\/.*)*\/?$/; - /** * If the discovery endpoint is available, the user will be able to choose to use it or not. * Otherwise, he will need to end the client configuration manually. @@ -109,7 +106,7 @@ export const OpenidConnectForm =

{t('app.admin.authentication.openid_connect_form.client_options')}

{currentFormValues?.client_auth_method === 'jwks' && } } diff --git a/app/frontend/src/javascript/components/editorial-block/editorial-block-form.tsx b/app/frontend/src/javascript/components/editorial-block/editorial-block-form.tsx index 8b7a69edd..3f8649621 100644 --- a/app/frontend/src/javascript/components/editorial-block/editorial-block-form.tsx +++ b/app/frontend/src/javascript/components/editorial-block/editorial-block-form.tsx @@ -5,6 +5,7 @@ import { FormSwitch } from '../form/form-switch'; import { FormRichText } from '../form/form-rich-text'; import { FormInput } from '../form/form-input'; import { SettingName, SettingValue } from '../../models/setting'; +import ValidationLib from '../../lib/validation'; export type EditorialKeys = 'active_text_block' | 'text_block' | 'active_cta' | 'cta_label' | 'cta_url'; interface EditorialBlockFormProps { @@ -15,9 +16,6 @@ interface EditorialBlockFormProps { keys: Record } -// regular expression to validate the input fields -const urlRegex = /^(https?:\/\/)([^.]+)\.(.{2,30})(\/.*)*\/?$/; - /** * Allows to create a formatted text and optional cta button in a form block, to be included in a resource form managed by react-hook-form. */ @@ -78,7 +76,7 @@ export const EditorialBlockForm: React.FC = ({ register formState={formState} rules={{ required: { value: isActiveCta, message: t('app.admin.editorial_block_form.url_is_required') }, - pattern: { value: urlRegex, message: t('app.admin.editorial_block_form.url_must_be_safe') } + pattern: { value: ValidationLib.urlRegex, message: t('app.admin.editorial_block_form.url_must_be_safe') } }} label={t('app.admin.editorial_block_form.cta_url')} /> } diff --git a/app/frontend/src/javascript/components/socials/edit-socials.tsx b/app/frontend/src/javascript/components/socials/edit-socials.tsx index 13beb3953..032d6b861 100644 --- a/app/frontend/src/javascript/components/socials/edit-socials.tsx +++ b/app/frontend/src/javascript/components/socials/edit-socials.tsx @@ -7,6 +7,7 @@ import Icons from '../../../../images/social-icons.svg'; import { FormInput } from '../form/form-input'; import { Trash } from 'phosphor-react'; import { useTranslation } from 'react-i18next'; +import ValidationLib from '../../lib/validation'; interface EditSocialsProps { register: UseFormRegister, @@ -21,8 +22,6 @@ interface EditSocialsProps { */ export const EditSocials = ({ register, setValue, networks, formState, disabled }: EditSocialsProps) => { const { t } = useTranslation('shared'); - // regular expression to validate the input fields - const urlRegex = /^(https?:\/\/)([^.]+)\.(.{2,30})(\/.*)*\/?$/; const initSelectedNetworks = networks.filter(el => !['', null, undefined].includes(el.url)); const [selectedNetworks, setSelectedNetworks] = useState(initSelectedNetworks); @@ -72,7 +71,7 @@ export const EditSocials = ({ register, setVal register={register} rules= {{ pattern: { - value: urlRegex, + value: ValidationLib.urlRegex, message: t('app.shared.edit_socials.website_invalid') } }} diff --git a/app/frontend/src/javascript/components/socials/fab-socials.tsx b/app/frontend/src/javascript/components/socials/fab-socials.tsx index eb56a1d95..e1bd046e1 100644 --- a/app/frontend/src/javascript/components/socials/fab-socials.tsx +++ b/app/frontend/src/javascript/components/socials/fab-socials.tsx @@ -12,6 +12,7 @@ import Icons from '../../../../images/social-icons.svg'; import { Trash } from 'phosphor-react'; import { useTranslation } from 'react-i18next'; import { FabButton } from '../base/fab-button'; +import ValidationLib from '../../lib/validation'; declare const Application: IApplication; @@ -26,8 +27,6 @@ interface FabSocialsProps { */ export const FabSocials: React.FC = ({ show = false, onError, onSuccess }) => { const { t } = useTranslation('shared'); - // regular expression to validate the input fields - const urlRegex = /^(https?:\/\/)([\da-z.-]+)\.([-a-z\d.]{2,30})([/\w .-]*)*\/?$/; const { handleSubmit, register, setValue, formState } = useForm(); @@ -109,7 +108,7 @@ export const FabSocials: React.FC = ({ show = false, onError, o register={register} rules={{ pattern: { - value: urlRegex, + value: ValidationLib.urlRegex, message: t('app.shared.fab_socials.website_invalid') } }} diff --git a/app/frontend/src/javascript/components/user/user-profile-form.tsx b/app/frontend/src/javascript/components/user/user-profile-form.tsx index 768980bc9..f5125fb23 100644 --- a/app/frontend/src/javascript/components/user/user-profile-form.tsx +++ b/app/frontend/src/javascript/components/user/user-profile-form.tsx @@ -32,6 +32,7 @@ import { ProfileCustomField } from '../../models/profile-custom-field'; import { SettingName } from '../../models/setting'; import SettingAPI from '../../api/setting'; import { SelectOption } from '../../models/select'; +import ValidationLib from '../../lib/validation'; declare const Application: IApplication; @@ -55,10 +56,6 @@ interface UserProfileFormProps { export const UserProfileForm: React.FC = ({ action, size, user, operator, className, onError, onSuccess, showGroupInput, showTermsAndConditionsInput, showTrainingsInput, showTagsInput }) => { const { t } = useTranslation('shared'); - // regular expression to validate the input fields - const phoneRegex = /^((00|\+)\d{2,3})?[\d -]{4,14}$/; - const urlRegex = /^(https?:\/\/)([^.]+)\.(.{2,30})(\/.*)*\/?$/; - const { handleSubmit, register, control, formState, setValue, reset } = useForm({ defaultValues: { ...user } }); const output = useWatch({ control }); @@ -215,7 +212,7 @@ export const UserProfileForm: React.FC = ({ action, size, register={register} rules={{ pattern: { - value: phoneRegex, + value: ValidationLib.phoneRegex, message: t('app.shared.user_profile_form.phone_number_invalid') }, required: fieldsSettings.get('phone_required') === 'true' @@ -314,7 +311,7 @@ export const UserProfileForm: React.FC = ({ action, size, register={register} rules={{ pattern: { - value: urlRegex, + value: ValidationLib.urlRegex, message: t('app.shared.user_profile_form.website_invalid') } }} diff --git a/app/frontend/src/javascript/lib/validation.ts b/app/frontend/src/javascript/lib/validation.ts new file mode 100644 index 000000000..3d5f0882a --- /dev/null +++ b/app/frontend/src/javascript/lib/validation.ts @@ -0,0 +1,6 @@ +// Provides regular expressions to validate user inputs +export default class ValidationLib { + static urlRegex = /^(https?:\/\/)(([^.]+)\.)+(.{2,30})(\/.*)*\/?$/; + static endpointRegex = /^\/?([-._~:?#[\]@!$&'()*+,;=%\w]+\/?)*$/; + static phoneRegex = /^((00|\+)\d{2,3})?[\d -]{4,14}$/; +}