From f06662ef01f661f4b3b0be28ffba5b9afec7f983 Mon Sep 17 00:00:00 2001 From: Malik Zulqurnain Date: Tue, 13 May 2025 21:08:24 +0500 Subject: [PATCH 1/3] Fix `?` topic redirect --- libs/shared/src/utils.ts | 7 ++++++- .../scripts/views/pages/discussions/DiscussionsPage.tsx | 7 +++++-- 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/libs/shared/src/utils.ts b/libs/shared/src/utils.ts index e484ccd7f01..50ff264c13e 100644 --- a/libs/shared/src/utils.ts +++ b/libs/shared/src/utils.ts @@ -77,11 +77,16 @@ export const generateTopicIdentifiersFromUrl = (url: string) => { return generateTopicIdentifiersFromUrlPart(splitURLPath?.[2] || ''); }; +export const sanitizeTopicName = (name: string) => { + return name.replaceAll(`?`, ''); +}; + export const generateUrlPartForTopicIdentifiers = ( topicId: string | number | undefined, topicName: string, ) => { - return topicId ? `${topicId}-${topicName}` : `${topicName}`; + const _topicName = sanitizeTopicName(topicName); + return topicId ? `${topicId}-${_topicName}` : `${_topicName}`; }; // WARN: Using process.env to avoid webpack failures diff --git a/packages/commonwealth/client/scripts/views/pages/discussions/DiscussionsPage.tsx b/packages/commonwealth/client/scripts/views/pages/discussions/DiscussionsPage.tsx index 15d6eeb0f0e..750a9c5713e 100644 --- a/packages/commonwealth/client/scripts/views/pages/discussions/DiscussionsPage.tsx +++ b/packages/commonwealth/client/scripts/views/pages/discussions/DiscussionsPage.tsx @@ -27,6 +27,7 @@ import { formatDecimalToWei, generateTopicIdentifiersFromUrl, generateUrlPartForTopicIdentifiers, + sanitizeTopicName, } from '@hicommonwealth/shared'; import { useGetUserEthBalanceQuery } from 'client/scripts/state/api/communityStake'; import useUserStore from 'client/scripts/state/ui/user'; @@ -127,7 +128,8 @@ const DiscussionsPage = () => { window.location.href, ); const topicObj = topics?.find( - ({ name }) => name === topicIdentifiersFromURL?.topicName, + ({ name }) => + sanitizeTopicName(name) === topicIdentifiersFromURL?.topicName, ); const topicId = topicObj?.id; @@ -227,7 +229,8 @@ const DiscussionsPage = () => { } const validTopic = topics?.find( - (topic) => topic?.name === topicIdentifiersFromURL.topicName, + (topic) => + sanitizeTopicName(topic?.name) === topicIdentifiersFromURL.topicName, ); if (!validTopic) { navigate('/discussions'); From e0ba371a7828c344ef74e870d3955276480b2b81 Mon Sep 17 00:00:00 2001 From: Malik Zulqurnain Date: Tue, 13 May 2025 21:11:54 +0500 Subject: [PATCH 2/3] Disallow `?` char for topic names --- .../Topics/TopicDetails/CreateTopicsSection/validation.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/commonwealth/client/scripts/views/pages/CommunityManagement/Topics/TopicDetails/CreateTopicsSection/validation.ts b/packages/commonwealth/client/scripts/views/pages/CommunityManagement/Topics/TopicDetails/CreateTopicsSection/validation.ts index 782a9fcd5c5..952637db265 100644 --- a/packages/commonwealth/client/scripts/views/pages/CommunityManagement/Topics/TopicDetails/CreateTopicsSection/validation.ts +++ b/packages/commonwealth/client/scripts/views/pages/CommunityManagement/Topics/TopicDetails/CreateTopicsSection/validation.ts @@ -7,13 +7,13 @@ export const topicCreationValidationSchema = z.object({ .string({ invalid_type_error: VALIDATION_MESSAGES.NO_INPUT }) .min(1, { message: VALIDATION_MESSAGES.NO_INPUT }) .superRefine((value, ctx) => { - const disallowedCharMatches = value.match(/["<>%{}|\\/^`]/g); + const disallowedCharMatches = value.match(/["<>%{}|\\/^`?]/g); if (disallowedCharMatches) { - const errMsg = `The ${pluralizeWithoutNumberPrefix( + const errMsg = `These ${pluralizeWithoutNumberPrefix( disallowedCharMatches.length, 'char', - )} ${disallowedCharMatches.join(', ')} are not permitted`; + )} are not permitted: ${disallowedCharMatches.join(', ')}`; ctx.addIssue({ code: z.ZodIssueCode.custom, From ec6a4576cdffe2d1c86e6d1a1980ff137f9baa72 Mon Sep 17 00:00:00 2001 From: Malik Zulqurnain Date: Tue, 13 May 2025 21:16:08 +0500 Subject: [PATCH 3/3] Updated remaining instances of disallowed topic name regex --- libs/schemas/src/entities/topic.schemas.ts | 3 ++- libs/shared/src/utils.ts | 2 ++ .../client/scripts/views/modals/edit_topic_modal.tsx | 5 ++++- .../Topics/TopicDetails/CreateTopicsSection/validation.ts | 3 ++- 4 files changed, 10 insertions(+), 3 deletions(-) diff --git a/libs/schemas/src/entities/topic.schemas.ts b/libs/schemas/src/entities/topic.schemas.ts index cdbb989f8ab..b07b5dca338 100644 --- a/libs/schemas/src/entities/topic.schemas.ts +++ b/libs/schemas/src/entities/topic.schemas.ts @@ -1,3 +1,4 @@ +import { DISALLOWED_TOPIC_NAMES_REGEX } from '@hicommonwealth/shared'; import { z } from 'zod'; import { PG_INT } from '../utils'; @@ -15,7 +16,7 @@ export const Topic = z.object({ .max(255) .default('General') .refine( - (v) => !v.match(/["<>%{}|\\/^`]/g), + (v) => !v.match(DISALLOWED_TOPIC_NAMES_REGEX), 'Name must not contain special characters', ), community_id: z.string().max(255), diff --git a/libs/shared/src/utils.ts b/libs/shared/src/utils.ts index 50ff264c13e..ab4adc6e8ff 100644 --- a/libs/shared/src/utils.ts +++ b/libs/shared/src/utils.ts @@ -77,6 +77,8 @@ export const generateTopicIdentifiersFromUrl = (url: string) => { return generateTopicIdentifiersFromUrlPart(splitURLPath?.[2] || ''); }; +export const DISALLOWED_TOPIC_NAMES_REGEX = /["<>%{}|\\/^`?]/g; + export const sanitizeTopicName = (name: string) => { return name.replaceAll(`?`, ''); }; diff --git a/packages/commonwealth/client/scripts/views/modals/edit_topic_modal.tsx b/packages/commonwealth/client/scripts/views/modals/edit_topic_modal.tsx index 4810b2a70b0..18209ad71bb 100644 --- a/packages/commonwealth/client/scripts/views/modals/edit_topic_modal.tsx +++ b/packages/commonwealth/client/scripts/views/modals/edit_topic_modal.tsx @@ -18,6 +18,7 @@ import { } from '../components/component_kit/new_designs/CWModal'; import { openConfirmation } from './confirmation_modal'; +import { DISALLOWED_TOPIC_NAMES_REGEX } from '@hicommonwealth/shared'; import clsx from 'clsx'; import { notifySuccess } from 'controllers/app/notifications'; import { DeltaStatic } from 'quill'; @@ -199,7 +200,9 @@ export const EditTopicModal = ({ inputValidationFn={(text: string) => { let newErrorMsg; - const disallowedCharMatches = text.match(/["<>%{}|\\/^`]/g); + const disallowedCharMatches = text.match( + DISALLOWED_TOPIC_NAMES_REGEX, + ); if (disallowedCharMatches) { newErrorMsg = `The ${pluralizeWithoutNumberPrefix( disallowedCharMatches.length, diff --git a/packages/commonwealth/client/scripts/views/pages/CommunityManagement/Topics/TopicDetails/CreateTopicsSection/validation.ts b/packages/commonwealth/client/scripts/views/pages/CommunityManagement/Topics/TopicDetails/CreateTopicsSection/validation.ts index 952637db265..2eefbc692ff 100644 --- a/packages/commonwealth/client/scripts/views/pages/CommunityManagement/Topics/TopicDetails/CreateTopicsSection/validation.ts +++ b/packages/commonwealth/client/scripts/views/pages/CommunityManagement/Topics/TopicDetails/CreateTopicsSection/validation.ts @@ -1,3 +1,4 @@ +import { DISALLOWED_TOPIC_NAMES_REGEX } from '@hicommonwealth/shared'; import { pluralizeWithoutNumberPrefix } from 'helpers'; import { VALIDATION_MESSAGES } from 'helpers/formValidations/messages'; import z from 'zod'; @@ -7,7 +8,7 @@ export const topicCreationValidationSchema = z.object({ .string({ invalid_type_error: VALIDATION_MESSAGES.NO_INPUT }) .min(1, { message: VALIDATION_MESSAGES.NO_INPUT }) .superRefine((value, ctx) => { - const disallowedCharMatches = value.match(/["<>%{}|\\/^`?]/g); + const disallowedCharMatches = value.match(DISALLOWED_TOPIC_NAMES_REGEX); if (disallowedCharMatches) { const errMsg = `These ${pluralizeWithoutNumberPrefix(