From 809c16a7e33c0e0bd6b4c1fcaa50e65f1987e9f3 Mon Sep 17 00:00:00 2001 From: Ajay Bura <32841439+ajbura@users.noreply.github.com> Date: Sun, 4 Aug 2024 10:59:54 +0530 Subject: [PATCH] fix crash when decoding malformed urls --- src/app/components/editor/input.ts | 3 ++- src/app/components/url-preview/UrlPreviewCard.tsx | 3 ++- src/app/pages/auth/AuthLayout.tsx | 5 +++-- src/app/plugins/react-custom-html-parser.tsx | 9 +++++---- src/app/utils/dom.ts | 8 ++++++++ 5 files changed, 20 insertions(+), 8 deletions(-) diff --git a/src/app/components/editor/input.ts b/src/app/components/editor/input.ts index 29e5bd6a2..20c56ed31 100644 --- a/src/app/components/editor/input.ts +++ b/src/app/components/editor/input.ts @@ -25,6 +25,7 @@ import { parseMatrixToUser, testMatrixTo, } from '../../plugins/matrix-to'; +import { tryDecodeURIComponent } from '../../utils/dom'; const markNodeToType: Record = { b: MarkType.Bold, @@ -73,7 +74,7 @@ const elementToInlineNode = (node: Element): MentionElement | EmoticonElement | return createEmoticonElement(src, alt || 'Unknown Emoji'); } if (node.name === 'a') { - const href = decodeURIComponent(node.attribs.href); + const href = tryDecodeURIComponent(node.attribs.href); if (typeof href !== 'string') return undefined; if (testMatrixTo(href)) { const userMention = parseMatrixToUser(href); diff --git a/src/app/components/url-preview/UrlPreviewCard.tsx b/src/app/components/url-preview/UrlPreviewCard.tsx index fc9229faf..07c25f8a1 100644 --- a/src/app/components/url-preview/UrlPreviewCard.tsx +++ b/src/app/components/url-preview/UrlPreviewCard.tsx @@ -9,6 +9,7 @@ import { useIntersectionObserver, } from '../../hooks/useIntersectionObserver'; import * as css from './UrlPreviewCard.css'; +import { tryDecodeURIComponent } from '../../utils/dom'; const linkStyles = { color: color.Success.Main }; @@ -43,7 +44,7 @@ export const UrlPreviewCard = as<'div', { url: string; ts: number }>( priority="300" > {typeof prev['og:site_name'] === 'string' && `${prev['og:site_name']} | `} - {decodeURIComponent(url)} + {tryDecodeURIComponent(url)} {prev['og:title']} diff --git a/src/app/pages/auth/AuthLayout.tsx b/src/app/pages/auth/AuthLayout.tsx index 2ea941420..3943f42d1 100644 --- a/src/app/pages/auth/AuthLayout.tsx +++ b/src/app/pages/auth/AuthLayout.tsx @@ -29,6 +29,7 @@ import { AutoDiscoveryInfoProvider } from '../../hooks/useAutoDiscoveryInfo'; import { AuthFlowsLoader } from '../../components/AuthFlowsLoader'; import { AuthFlowsProvider } from '../../hooks/useAuthFlows'; import { AuthServerProvider } from '../../hooks/useAuthServer'; +import { tryDecodeURIComponent } from '../../utils/dom'; const currentAuthPath = (pathname: string): string => { if (matchPath(LOGIN_PATH, pathname)) { @@ -72,7 +73,7 @@ export function AuthLayout() { const clientConfig = useClientConfig(); const defaultServer = clientDefaultServer(clientConfig); - let server: string = urlEncodedServer ? decodeURIComponent(urlEncodedServer) : defaultServer; + let server: string = urlEncodedServer ? tryDecodeURIComponent(urlEncodedServer) : defaultServer; if (!clientAllowedServer(clientConfig, server)) { server = defaultServer; @@ -94,7 +95,7 @@ export function AuthLayout() { // if server is mismatches with path server, update path useEffect(() => { - if (!urlEncodedServer || decodeURIComponent(urlEncodedServer) !== server) { + if (!urlEncodedServer || tryDecodeURIComponent(urlEncodedServer) !== server) { navigate( generatePath(currentAuthPath(location.pathname), { server: encodeURIComponent(server), diff --git a/src/app/plugins/react-custom-html-parser.tsx b/src/app/plugins/react-custom-html-parser.tsx index 167043745..95e2f3342 100644 --- a/src/app/plugins/react-custom-html-parser.tsx +++ b/src/app/plugins/react-custom-html-parser.tsx @@ -26,6 +26,7 @@ import { testMatrixTo, } from './matrix-to'; import { onEnterOrSpace } from '../utils/keyboard'; +import { tryDecodeURIComponent } from '../utils/dom'; const ReactPrism = lazy(() => import('./react-prism/ReactPrism')); @@ -134,8 +135,8 @@ export const factoryRenderLinkifyWithMention = ( attributes, content, }) => { - if (tagName === 'a' && testMatrixTo(decodeURIComponent(attributes.href))) { - const mention = mentionRender(decodeURIComponent(attributes.href)); + if (tagName === 'a' && testMatrixTo(tryDecodeURIComponent(attributes.href))) { + const mention = mentionRender(tryDecodeURIComponent(attributes.href)); if (mention) return mention; } @@ -325,11 +326,11 @@ export const getReactCustomHtmlParser = ( } } - if (name === 'a' && testMatrixTo(decodeURIComponent(props.href))) { + if (name === 'a' && testMatrixTo(tryDecodeURIComponent(props.href))) { const mention = renderMatrixMention( mx, roomId, - decodeURIComponent(props.href), + tryDecodeURIComponent(props.href), makeMentionCustomProps(params.handleMentionClick) ); if (mention) return mention; diff --git a/src/app/utils/dom.ts b/src/app/utils/dom.ts index 1aea6754c..ab4b8e65c 100644 --- a/src/app/utils/dom.ts +++ b/src/app/utils/dom.ts @@ -196,3 +196,11 @@ export const setFavicon = (url: string): void => { if (!favicon) return; favicon.setAttribute('href', url); }; + +export const tryDecodeURIComponent = (encodedURIComponent: string): string => { + try { + return decodeURIComponent(encodedURIComponent); + } catch { + return encodedURIComponent; + } +};