Skip to content

Commit

Permalink
Merge branch 'develop' into refactor/react-node
Browse files Browse the repository at this point in the history
  • Loading branch information
tassoevan authored Jan 9, 2025
2 parents d56087d + 4aa95b6 commit 0beaeb5
Show file tree
Hide file tree
Showing 51 changed files with 910 additions and 284 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)
9 changes: 9 additions & 0 deletions .changeset/fifty-apricots-clean.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
---
"@rocket.chat/omnichannel-services": patch
---

Fixes a behavior when running microservices that caused queue worker to process just the first 60 seconds of request.

This was due to a mistakenly bound context. Queue Worker was changed to start doing work only after it received the first request.

However, with the introduction of ASL and actual context on calls, the worker registration was absorbing the context of the call that created them, causing service calls happening inside the callbacks to fail because of a timeout.
5 changes: 5 additions & 0 deletions .changeset/kind-ducks-thank.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@rocket.chat/meteor': patch
---

Fixes apps actions showing in toolbar without an icon
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
Loading

0 comments on commit 0beaeb5

Please sign in to comment.