Skip to content

Commit

Permalink
fix: imported fixes 25-01-07 (#34904)
Browse files Browse the repository at this point in the history
  • Loading branch information
julio-rocketchat authored Jan 8, 2025
1 parent 1cc2bc7 commit c7be829
Show file tree
Hide file tree
Showing 42 changed files with 442 additions and 185 deletions.
5 changes: 5 additions & 0 deletions .changeset/breezy-horses-marry.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@rocket.chat/meteor': patch
---

Security Hotfix (https://docs.rocket.chat/docs/security-fixes-and-updates)
5 changes: 5 additions & 0 deletions apps/meteor/app/cors/server/cors.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import type { UrlWithParsedQuery } from 'url';
import url from 'url';

import { Logger } from '@rocket.chat/logger';
import { OAuthApps } from '@rocket.chat/models';
import { Meteor } from 'meteor/meteor';
import type { StaticFiles } from 'meteor/webapp';
import { WebApp, WebAppInternals } from 'meteor/webapp';
Expand Down Expand Up @@ -48,10 +49,13 @@ WebApp.rawConnectHandlers.use(async (_req: http.IncomingMessage, res: http.Serve
}

if (settings.get<boolean>('Enable_CSP')) {
const legacyZapierAvailable = Boolean(await OAuthApps.findOneById('zapier'));

// eslint-disable-next-line @typescript-eslint/naming-convention
const cdn_prefixes = [
settings.get<string>('CDN_PREFIX'),
settings.get<string>('CDN_PREFIX_ALL') ? null : settings.get<string>('CDN_JSCSS_PREFIX'),
legacyZapierAvailable && 'https://cdn.zapier.com',
]
.filter(Boolean)
.join(' ');
Expand All @@ -68,6 +72,7 @@ WebApp.rawConnectHandlers.use(async (_req: http.IncomingMessage, res: http.Serve
settings.get<boolean>('Accounts_OAuth_Apple') && 'https://appleid.cdn-apple.com',
settings.get<boolean>('PiwikAnalytics_enabled') && settings.get('PiwikAnalytics_url'),
settings.get<boolean>('GoogleAnalytics_enabled') && 'https://www.google-analytics.com',
legacyZapierAvailable && 'https://zapier.com',
...settings
.get<string>('Extra_CSP_Domains')
.split(/[ \n\,]/gim)
Expand Down
1 change: 0 additions & 1 deletion apps/meteor/app/oauth2-server-config/server/index.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import './oauth/oauth2-server';
import './oauth/default-services';
import './admin/functions/addOAuthApp';
import './admin/methods/updateOAuthApp';
import './admin/methods/deleteOAuthApp';

This file was deleted.

8 changes: 6 additions & 2 deletions apps/meteor/client/components/FingerprintChangeModal.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { Box } from '@rocket.chat/fuselage';
import DOMPurify from 'dompurify';
import type { ReactElement } from 'react';
import { useTranslation } from 'react-i18next';

Expand Down Expand Up @@ -26,14 +27,17 @@ const FingerprintChangeModal = ({ onConfirm, onCancel, onClose }: FingerprintCha
is='p'
mbe={16}
dangerouslySetInnerHTML={{
__html: t('Unique_ID_change_detected_description'),
__html: DOMPurify.sanitize(t('Unique_ID_change_detected_description')),
}}
/>
<Box
is='p'
mbe={16}
dangerouslySetInnerHTML={{
__html: t('Unique_ID_change_detected_learn_more_link'),
__html: DOMPurify.sanitize(t('Unique_ID_change_detected_learn_more_link'), {
ALLOWED_TAGS: ['b', 'i', 'em', 'strong', 'a'],
ALLOWED_ATTR: ['href', 'title'],
}),
}}
/>
</GenericModal>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { Box } from '@rocket.chat/fuselage';
import DOMPurify from 'dompurify';
import type { ReactElement } from 'react';
import { useTranslation } from 'react-i18next';

Expand Down Expand Up @@ -29,14 +30,19 @@ const FingerprintChangeModalConfirmation = ({
is='p'
mbe={16}
dangerouslySetInnerHTML={{
__html: newWorkspace ? t('Confirm_new_workspace_description') : t('Confirm_configuration_update_description'),
__html: newWorkspace
? DOMPurify.sanitize(t('Confirm_new_workspace_description'))
: DOMPurify.sanitize(t('Confirm_configuration_update_description')),
}}
/>
<Box
is='p'
mbe={16}
dangerouslySetInnerHTML={{
__html: t('Unique_ID_change_detected_learn_more_link'),
__html: DOMPurify.sanitize(t('Unique_ID_change_detected_learn_more_link'), {
ALLOWED_TAGS: ['b', 'i', 'em', 'strong', 'a'],
ALLOWED_ATTR: ['href', 'title'],
}),
}}
/>
</GenericModal>
Expand Down
5 changes: 4 additions & 1 deletion apps/meteor/client/components/RawText.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
import DOMPurify from 'dompurify';
import type { ReactElement } from 'react';

/** @deprecated */
const RawText = ({ children }: { children: string }): ReactElement => <span dangerouslySetInnerHTML={{ __html: children }} />;
const RawText = ({ children }: { children: string }): ReactElement => (
<span dangerouslySetInnerHTML={{ __html: DOMPurify.sanitize(children) }} />
);

export default RawText;
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import DOMPurify from 'dompurify';
import type { ReactNode } from 'react';
import { useCallback, useMemo } from 'react';
import { createPortal } from 'react-dom';
Expand Down Expand Up @@ -84,7 +85,11 @@ export const OmnichannelRoomIconProvider = ({ children }: OmnichannelRoomIconPro
xmlns='http://www.w3.org/2000/svg'
xmlnsXlink='http://www.w3.org/1999/xlink'
style={{ display: 'none' }}
dangerouslySetInnerHTML={{ __html: svgIcons.join('') }}
dangerouslySetInnerHTML={{
__html: DOMPurify.sanitize(svgIcons.join(''), {
USE_PROFILES: { svg: true, svgFilters: true },
}),
}}
/>,
document.body,
'custom-icons',
Expand Down
21 changes: 13 additions & 8 deletions apps/meteor/client/components/UrlChangeModal.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { Box } from '@rocket.chat/fuselage';
import DOMPurify from 'dompurify';
import type { ReactElement } from 'react';
import { useTranslation } from 'react-i18next';

Expand All @@ -19,18 +20,22 @@ const UrlChangeModal = ({ onConfirm, siteUrl, currentUrl, onClose }: UrlChangeMo
is='p'
mbe={16}
dangerouslySetInnerHTML={{
__html: t('The_setting_s_is_configured_to_s_and_you_are_accessing_from_s', {
postProcess: 'sprintf',
sprintf: [t('Site_Url'), siteUrl, currentUrl],
}),
__html: DOMPurify.sanitize(
t('The_setting_s_is_configured_to_s_and_you_are_accessing_from_s', {
postProcess: 'sprintf',
sprintf: [t('Site_Url'), siteUrl, currentUrl],
}),
),
}}
/>
<p
dangerouslySetInnerHTML={{
__html: t('Do_you_want_to_change_to_s_question', {
postProcess: 'sprintf',
sprintf: [currentUrl],
}),
__html: DOMPurify.sanitize(
t('Do_you_want_to_change_to_s_question', {
postProcess: 'sprintf',
sprintf: [currentUrl],
}),
),
}}
/>
</GenericModal>
Expand Down
15 changes: 14 additions & 1 deletion apps/meteor/client/lib/utils/createToken.ts
Original file line number Diff line number Diff line change
@@ -1 +1,14 @@
export const createToken = (): string => Math.random().toString(36).substring(2, 15) + Math.random().toString(36).substring(2, 15);
export const createToken = (): string => {
const array = new Uint8Array(16);
if (typeof window !== 'undefined' && window.crypto && window.crypto.getRandomValues) {
window.crypto.getRandomValues(array);
} else {
// Use Node.js crypto
const { randomBytes } = require('crypto'); // eslint-disable-line @typescript-eslint/no-var-requires
const buffer = randomBytes(16);
array.set(buffer);
}
return Array.from(array)
.map((byte) => byte.toString(16).padStart(2, '0'))
.join('');
};
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import type { IMessage, IRoom, ISubscription } from '@rocket.chat/core-typings';
import { isDirectMessageRoom, isMultipleDirectMessageRoom, isOmnichannelRoom, isVideoConfMessage } from '@rocket.chat/core-typings';
import { Badge, Sidebar, SidebarItemAction, SidebarItemActions, Margins } from '@rocket.chat/fuselage';
import { useLayout } from '@rocket.chat/ui-contexts';
import DOMPurify from 'dompurify';
import type { TFunction } from 'i18next';
import type { AllHTMLAttributes, ComponentType, ReactElement, ReactNode } from 'react';
import { memo, useMemo } from 'react';
Expand Down Expand Up @@ -147,7 +148,9 @@ function SideBarItemTemplateWithData({
const { enabled: isPriorityEnabled } = useOmnichannelPriorities();

const message = extended && getMessage(room, lastMessage, t);
const subtitle = message ? <span className='message-body--unstyled' dangerouslySetInnerHTML={{ __html: message }} /> : null;
const subtitle = message ? (
<span className='message-body--unstyled' dangerouslySetInnerHTML={{ __html: DOMPurify.sanitize(message) }} />
) : null;

const threadUnread = tunread.length > 0;
const variant =
Expand Down
3 changes: 2 additions & 1 deletion apps/meteor/client/sidebar/footer/SidebarFooterDefault.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { css } from '@rocket.chat/css-in-js';
import { Box, SidebarDivider, Palette, SidebarFooter as Footer } from '@rocket.chat/fuselage';
import { useSetting } from '@rocket.chat/ui-contexts';
import { useThemeMode } from '@rocket.chat/ui-theming';
import DOMPurify from 'dompurify';
import type { ReactElement } from 'react';

import { SidebarFooterWatermark } from './SidebarFooterWatermark';
Expand Down Expand Up @@ -32,7 +33,7 @@ const SidebarFooterDefault = (): ReactElement => {
width='auto'
className={sidebarFooterStyle}
dangerouslySetInnerHTML={{
__html: logo,
__html: DOMPurify.sanitize(logo),
}}
/>
<SidebarFooterWatermark />
Expand Down
3 changes: 2 additions & 1 deletion apps/meteor/client/sidebarv2/footer/SidebarFooterDefault.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { css } from '@rocket.chat/css-in-js';
import { Box, SidebarDivider, Palette, SidebarFooter as Footer } from '@rocket.chat/fuselage';
import { useSetting } from '@rocket.chat/ui-contexts';
import { useThemeMode } from '@rocket.chat/ui-theming';
import DOMPurify from 'dompurify';
import type { ReactElement } from 'react';

import { SidebarFooterWatermark } from './SidebarFooterWatermark';
Expand Down Expand Up @@ -32,7 +33,7 @@ const SidebarFooterDefault = (): ReactElement => {
width='auto'
className={sidebarFooterStyle}
dangerouslySetInnerHTML={{
__html: logo,
__html: DOMPurify.sanitize(logo),
}}
/>
<SidebarFooterWatermark />
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { AccordionItem, ButtonGroup, Button, Box } from '@rocket.chat/fuselage';
import { useSetModal, useToastMessageDispatch, useMethod } from '@rocket.chat/ui-contexts';
import DOMPurify from 'dompurify';
import { useCallback } from 'react';
import { useTranslation } from 'react-i18next';

Expand All @@ -23,7 +24,7 @@ const PreferencesMyDataSection = () => {
setModal(
<MyDataModal
title={t('UserDataDownload_Requested')}
text={<Box dangerouslySetInnerHTML={{ __html: text }} />}
text={<Box dangerouslySetInnerHTML={{ __html: DOMPurify.sanitize(text) }} />}
onCancel={() => setModal(null)}
/>,
);
Expand All @@ -41,7 +42,7 @@ const PreferencesMyDataSection = () => {
setModal(
<MyDataModal
title={t('UserDataDownload_Requested')}
text={<Box dangerouslySetInnerHTML={{ __html: text }} />}
text={<Box dangerouslySetInnerHTML={{ __html: DOMPurify.sanitize(text) }} />}
onCancel={() => setModal(null)}
/>,
);
Expand All @@ -55,7 +56,7 @@ const PreferencesMyDataSection = () => {
setModal(
<MyDataModal
title={t('UserDataDownload_Requested')}
text={<Box dangerouslySetInnerHTML={{ __html: text }} />}
text={<Box dangerouslySetInnerHTML={{ __html: DOMPurify.sanitize(text) }} />}
onCancel={() => setModal(null)}
/>,
);
Expand Down
5 changes: 3 additions & 2 deletions apps/meteor/client/views/account/security/EndToEnd.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { Box, PasswordInput, Field, FieldGroup, FieldLabel, FieldRow, FieldError, FieldHint, Button, Divider } from '@rocket.chat/fuselage';
import { useUniqueId } from '@rocket.chat/fuselage-hooks';
import { useToastMessageDispatch, useMethod, useTranslation, useLogout } from '@rocket.chat/ui-contexts';
import DOMPurify from 'dompurify';
import { Accounts } from 'meteor/accounts-base';
import type { ComponentProps, ReactElement } from 'react';
import { useCallback, useEffect } from 'react';
Expand Down Expand Up @@ -76,7 +77,7 @@ const EndToEnd = (props: ComponentProps<typeof Box>): ReactElement => {
is='p'
fontScale='p1'
id={e2ePasswordExplanationId}
dangerouslySetInnerHTML={{ __html: t('E2E_Encryption_Password_Explanation') }}
dangerouslySetInnerHTML={{ __html: DOMPurify.sanitize(t('E2E_Encryption_Password_Explanation')) }}
/>

<Box mbs={36} w='full'>
Expand Down Expand Up @@ -160,7 +161,7 @@ const EndToEnd = (props: ComponentProps<typeof Box>): ReactElement => {
<Box is='h4' fontScale='h4' mbe={12}>
{t('Reset_E2E_Key')}
</Box>
<Box is='p' fontScale='p1' mbe={12} dangerouslySetInnerHTML={{ __html: t('E2E_Reset_Key_Explanation') }} />
<Box is='p' fontScale='p1' mbe={12} dangerouslySetInnerHTML={{ __html: DOMPurify.sanitize(t('E2E_Reset_Key_Explanation')) }} />
<Button onClick={handleResetE2eKey} data-qa-type='e2e-encryption-reset-key-button'>
{t('Reset_E2E_Key')}
</Button>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { Box, Pagination, States, StatesAction, StatesActions, StatesIcon, StatesSubtitle, StatesTitle } from '@rocket.chat/fuselage';
import { useSetModal, useToastMessageDispatch, useUserId, useMethod } from '@rocket.chat/ui-contexts';
import DOMPurify from 'dompurify';
import type { ReactElement, RefObject } from 'react';
import { useMemo, useCallback } from 'react';
import { useTranslation } from 'react-i18next';
Expand Down Expand Up @@ -68,10 +69,12 @@ const AccountTokensTable = (): ReactElement => {
<GenericModal title={t('API_Personal_Access_Token_Generated')} onConfirm={closeModal}>
<Box
dangerouslySetInnerHTML={{
__html: t('API_Personal_Access_Token_Generated_Text_Token_s_UserId_s', {
token,
userId,
}),
__html: DOMPurify.sanitize(
t('API_Personal_Access_Token_Generated_Text_Token_s_UserId_s', {
token,
userId,
}),
),
}}
/>
</GenericModal>,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import type { SelectOption } from '@rocket.chat/fuselage';
import { Box, TextInput, Button, Margins, Select } from '@rocket.chat/fuselage';
import { useSetModal, useToastMessageDispatch, useUserId, useMethod } from '@rocket.chat/ui-contexts';
import DOMPurify from 'dompurify';
import { useCallback, useMemo, useEffect } from 'react';
import { Controller, useForm } from 'react-hook-form';
import { useTranslation } from 'react-i18next';
Expand Down Expand Up @@ -50,10 +51,12 @@ const AddToken = ({ reload }: AddTokenProps) => {
<GenericModal title={t('API_Personal_Access_Token_Generated')} onConfirm={() => setModal(null)} onClose={() => setModal(null)}>
<Box
dangerouslySetInnerHTML={{
__html: t('API_Personal_Access_Token_Generated_Text_Token_s_UserId_s', {
token,
userId,
}),
__html: DOMPurify.sanitize(
t('API_Personal_Access_Token_Generated_Text_Token_s_UserId_s', {
token,
userId,
}),
),
}}
/>
</GenericModal>,
Expand Down
15 changes: 14 additions & 1 deletion apps/meteor/client/views/admin/integrations/NewBot.tsx
Original file line number Diff line number Diff line change
@@ -1,10 +1,23 @@
import { Box } from '@rocket.chat/fuselage';
import DOMPurify from 'dompurify';
import { useTranslation } from 'react-i18next';

const NewBot = () => {
const { t } = useTranslation();

return <Box pb={20} fontScale='h4' key='bots' dangerouslySetInnerHTML={{ __html: t('additional_integrations_Bots') }} />;
return (
<Box
pb={20}
fontScale='h4'
key='bots'
dangerouslySetInnerHTML={{
__html: DOMPurify.sanitize(t('additional_integrations_Bots'), {
ALLOWED_TAGS: ['a'],
ALLOWED_ATTR: ['href', 'target'],
}),
}}
/>
);
};

export default NewBot;
Loading

0 comments on commit c7be829

Please sign in to comment.