Skip to content

Commit

Permalink
Merge branch 'develop' of github.com:RocketChat/Rocket.Chat into feat…
Browse files Browse the repository at this point in the history
…/mentionBot

* 'develop' of github.com:RocketChat/Rocket.Chat:
  fix: Auto-translate doesn't work on E2E rooms (#30369)
  test: Validate monitors data access (#30593)
  fix: reset file input after uploading file (#30529)
  refactor: AutoCompleteTagsMultiple to TS (#30577)
  fix: DM room stay "read only" after the deactivate and reactivate user with "guest" role (#30459)
  fix: Change plan name from Enterprise to Premium on marketplace filtering (#30616)
  regression: test license from cloud (#30609)
  fix: Unable to send attachments via email as an omni-agent (#30525)
  ci: fix lint task
  fix: cloud alerts (#30607)
  feat: License trigger cloud sync after reach limits (#30603)
  chore: Change plan name Enterprise to Premium on marketplace (#30487)
  chore: Improve cache of static files (#30290)
  regression: Undefined MAC count on startup cloud sync (#30605)
  chore: Change Records page name to Reports (#30513)
  • Loading branch information
gabriellsh committed Oct 11, 2023
2 parents 2d231f6 + 223dce1 commit c7e9a78
Show file tree
Hide file tree
Showing 60 changed files with 692 additions and 167 deletions.
5 changes: 5 additions & 0 deletions .changeset/eleven-gorillas-deliver.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@rocket.chat/meteor': patch
---

Fix trying to upload same file again and again.
5 changes: 5 additions & 0 deletions .changeset/gentle-radios-relate.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@rocket.chat/meteor": patch
---

Fixed DM room with "guest" user kept as "read only" after reactivating user
5 changes: 5 additions & 0 deletions .changeset/heavy-ads-carry.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@rocket.chat/meteor": patch
---

fix: Change plan name from Enterprise to Premium on marketplace filtering
5 changes: 5 additions & 0 deletions .changeset/odd-hounds-thank.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@rocket.chat/meteor": patch
---

chore: Change plan name Enterprise to Premium on marketplace
6 changes: 6 additions & 0 deletions .changeset/popular-actors-cheat.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
"@rocket.chat/meteor": patch
"@rocket.chat/model-typings": patch
---

Do not allow auto-translation to be enabled in E2E rooms
5 changes: 5 additions & 0 deletions .changeset/proud-shrimps-cheat.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@rocket.chat/meteor": patch
---

fix: Unable to send attachments via email as an omni-agent
5 changes: 5 additions & 0 deletions .changeset/shiny-pillows-run.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@rocket.chat/meteor": patch
---

fix: cloud alerts not working
5 changes: 5 additions & 0 deletions .changeset/wicked-humans-hang.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@rocket.chat/meteor": patch
---

Improve cache of static files
9 changes: 8 additions & 1 deletion apps/meteor/app/autotranslate/server/methods/saveSettings.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { Subscriptions } from '@rocket.chat/models';
import { Subscriptions, Rooms } from '@rocket.chat/models';
import type { ServerMethods } from '@rocket.chat/ui-contexts';
import { check } from 'meteor/check';
import { Meteor } from 'meteor/meteor';
Expand Down Expand Up @@ -46,6 +46,13 @@ Meteor.methods<ServerMethods>({

switch (field) {
case 'autoTranslate':
const room = await Rooms.findE2ERoomById(rid, { projection: { _id: 1 } });
if (room && value === '1') {
throw new Meteor.Error('error-e2e-enabled', 'Enabling auto-translation in E2E encrypted rooms is not allowed', {
method: 'saveAutoTranslateSettings',
});
}

await Subscriptions.updateAutoTranslateById(subscription._id, value === '1');
if (!subscription.autoTranslateLanguage && options.defaultLanguage) {
await Subscriptions.updateAutoTranslateLanguageById(subscription._id, options.defaultLanguage);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { Message } from '@rocket.chat/core-services';
import type { IUser } from '@rocket.chat/core-typings';
import { isRegisterUser } from '@rocket.chat/core-typings';
import { Rooms } from '@rocket.chat/models';
import { Rooms, Subscriptions } from '@rocket.chat/models';
import { Match } from 'meteor/check';
import { Meteor } from 'meteor/meteor';
import type { UpdateResult } from 'mongodb';
Expand All @@ -25,5 +25,9 @@ export const saveRoomEncrypted = async function (rid: string, encrypted: boolean

await Message.saveSystemMessage(type, rid, user.username, user);
}

if (encrypted) {
await Subscriptions.disableAutoTranslateByRoomId(rid);
}
return update;
};
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,7 @@ export async function buildWorkspaceRegistrationData<T extends string | undefine
setupComplete: setupWizardState === 'completed',
connectionDisable: !registerServer,
npsEnabled,
MAC: stats.omnichannelContactsBySource.contactsCount,
MAC: stats.omnichannelContactsBySource?.contactsCount ?? 0,
// activeContactsBillingMonth: stats.omnichannelContactsBySource.contactsCount,
// activeContactsYesterday: stats.uniqueContactsOfYesterday.contactsCount,
};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ export async function getWorkspaceLicense(): Promise<{ updated: boolean; license

const payload = await fetchCloudWorkspaceLicensePayload({ token });

if (Date.parse(payload.updatedAt) <= currentLicense._updatedAt.getTime()) {
if (currentLicense.value && Date.parse(payload.updatedAt) <= currentLicense._updatedAt.getTime()) {
return fromCurrentLicense();
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,7 @@ export async function announcementSync() {
} catch (err) {
SystemLogger.error({
msg: 'Failed to sync with Rocket.Chat Cloud',
url: '/sync',
url: '/comms/workspace',
err,
});
}
Expand Down
6 changes: 4 additions & 2 deletions apps/meteor/app/cloud/server/functions/syncWorkspace/index.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { SystemLogger } from '../../../../../server/lib/logger/system';
import { CloudWorkspaceAccessTokenError } from '../getWorkspaceAccessToken';
import { getCachedSupportedVersionsToken } from '../supportedVersionsToken/supportedVersionsToken';
import { announcementSync } from './announcementSync';
Expand All @@ -7,10 +8,11 @@ export async function syncWorkspace() {
try {
await syncCloudData();
await announcementSync();
} catch (error) {
if (error instanceof CloudWorkspaceAccessTokenError) {
} catch (err) {
if (err instanceof CloudWorkspaceAccessTokenError) {
// TODO: Remove License if there is no access token
}
SystemLogger.error({ msg: 'Error during workspace sync', err });
}

await getCachedSupportedVersionsToken.reset();
Expand Down
41 changes: 41 additions & 0 deletions apps/meteor/app/cors/server/cors.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
import { createHash } from 'crypto';
import type http from 'http';
import type { UrlWithParsedQuery } from 'url';
import url from 'url';

import { Logger } from '@rocket.chat/logger';
Expand Down Expand Up @@ -77,6 +79,19 @@ WebApp.rawConnectHandlers.use((_req: http.IncomingMessage, res: http.ServerRespo
});

const _staticFilesMiddleware = WebAppInternals.staticFilesMiddleware;
declare module 'meteor/webapp' {
// eslint-disable-next-line @typescript-eslint/no-namespace
namespace WebApp {
function categorizeRequest(
req: http.IncomingMessage,
): { arch: string; path: string; url: UrlWithParsedQuery } & Record<string, unknown>;
}
}

// These routes already handle cache control on their own
const cacheControlledRoutes: Array<RegExp> = ['/assets', '/custom-sounds', '/emoji-custom', '/avatar', '/file-upload'].map(
(route) => new RegExp(`^${route}`, 'i'),
);

// @ts-expect-error - accessing internal property of webapp
WebAppInternals.staticFilesMiddleware = function (
Expand All @@ -86,6 +101,32 @@ WebAppInternals.staticFilesMiddleware = function (
next: NextFunction,
) {
res.setHeader('Access-Control-Allow-Origin', '*');
const { arch, path, url } = WebApp.categorizeRequest(req);

if (Meteor.isProduction && !cacheControlledRoutes.some((regexp) => regexp.test(path))) {
res.setHeader('Cache-Control', 'public, max-age=31536000');
}

// Prevent meteor_runtime_config.js to load from a different expected hash possibly causing
// a cache of the file for the wrong hash and start a client loop due to the mismatch
// of the hashes of ui versions which would be checked against a websocket response
if (path === '/meteor_runtime_config.js') {
const program = WebApp.clientPrograms[arch] as (typeof WebApp.clientPrograms)[string] & {
meteorRuntimeConfigHash?: string;
meteorRuntimeConfig: string;
};

if (!program?.meteorRuntimeConfigHash) {
program.meteorRuntimeConfigHash = createHash('sha1')
.update(JSON.stringify(encodeURIComponent(program.meteorRuntimeConfig)))
.digest('hex');
}

if (program.meteorRuntimeConfigHash !== url.query.hash) {
res.writeHead(404);
return res.end();
}
}
return _staticFilesMiddleware(staticFiles, req, res, next);
};

Expand Down
29 changes: 15 additions & 14 deletions apps/meteor/app/custom-sounds/client/lib/CustomSounds.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,21 +7,22 @@ import { getURL } from '../../../utils/client';
import { sdk } from '../../../utils/client/lib/SDKClient';

const getCustomSoundId = (soundId: ICustomSound['_id']) => `custom-sound-${soundId}`;
const getAssetUrl = (asset: string, params?: Record<string, any>) => getURL(asset, params, undefined, true);

const defaultSounds = [
{ _id: 'chime', name: 'Chime', extension: 'mp3', src: getURL('sounds/chime.mp3') },
{ _id: 'door', name: 'Door', extension: 'mp3', src: getURL('sounds/door.mp3') },
{ _id: 'beep', name: 'Beep', extension: 'mp3', src: getURL('sounds/beep.mp3') },
{ _id: 'chelle', name: 'Chelle', extension: 'mp3', src: getURL('sounds/chelle.mp3') },
{ _id: 'ding', name: 'Ding', extension: 'mp3', src: getURL('sounds/ding.mp3') },
{ _id: 'droplet', name: 'Droplet', extension: 'mp3', src: getURL('sounds/droplet.mp3') },
{ _id: 'highbell', name: 'Highbell', extension: 'mp3', src: getURL('sounds/highbell.mp3') },
{ _id: 'seasons', name: 'Seasons', extension: 'mp3', src: getURL('sounds/seasons.mp3') },
{ _id: 'telephone', name: 'Telephone', extension: 'mp3', src: getURL('sounds/telephone.mp3') },
{ _id: 'outbound-call-ringing', name: 'Outbound Call Ringing', extension: 'mp3', src: getURL('sounds/outbound-call-ringing.mp3') },
{ _id: 'call-ended', name: 'Call Ended', extension: 'mp3', src: getURL('sounds/call-ended.mp3') },
{ _id: 'dialtone', name: 'Dialtone', extension: 'mp3', src: getURL('sounds/dialtone.mp3') },
{ _id: 'ringtone', name: 'Ringtone', extension: 'mp3', src: getURL('sounds/ringtone.mp3') },
{ _id: 'chime', name: 'Chime', extension: 'mp3', src: getAssetUrl('sounds/chime.mp3') },
{ _id: 'door', name: 'Door', extension: 'mp3', src: getAssetUrl('sounds/door.mp3') },
{ _id: 'beep', name: 'Beep', extension: 'mp3', src: getAssetUrl('sounds/beep.mp3') },
{ _id: 'chelle', name: 'Chelle', extension: 'mp3', src: getAssetUrl('sounds/chelle.mp3') },
{ _id: 'ding', name: 'Ding', extension: 'mp3', src: getAssetUrl('sounds/ding.mp3') },
{ _id: 'droplet', name: 'Droplet', extension: 'mp3', src: getAssetUrl('sounds/droplet.mp3') },
{ _id: 'highbell', name: 'Highbell', extension: 'mp3', src: getAssetUrl('sounds/highbell.mp3') },
{ _id: 'seasons', name: 'Seasons', extension: 'mp3', src: getAssetUrl('sounds/seasons.mp3') },
{ _id: 'telephone', name: 'Telephone', extension: 'mp3', src: getAssetUrl('sounds/telephone.mp3') },
{ _id: 'outbound-call-ringing', name: 'Outbound Call Ringing', extension: 'mp3', src: getAssetUrl('sounds/outbound-call-ringing.mp3') },
{ _id: 'call-ended', name: 'Call Ended', extension: 'mp3', src: getAssetUrl('sounds/call-ended.mp3') },
{ _id: 'dialtone', name: 'Dialtone', extension: 'mp3', src: getAssetUrl('sounds/dialtone.mp3') },
{ _id: 'ringtone', name: 'Ringtone', extension: 'mp3', src: getAssetUrl('sounds/ringtone.mp3') },
];

class CustomSoundsClass {
Expand Down Expand Up @@ -85,7 +86,7 @@ class CustomSoundsClass {
}

getURL(sound: ICustomSound) {
return getURL(`/custom-sounds/${sound._id}.${sound.extension}?_dc=${sound.random || 0}`);
return getAssetUrl(`/custom-sounds/${sound._id}.${sound.extension}`, { _dc: sound.random || 0 });
}

getList() {
Expand Down
24 changes: 17 additions & 7 deletions apps/meteor/app/ui-master/server/inject.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ const callback: NextHandleFunction = (req, res, next) => {
return;
}

const injection = headInjections.get(pathname.replace(/^\//, '')) as Injection | undefined;
const injection = headInjections.get(pathname.replace(/^\//, '').split('_')[0]) as Injection | undefined;

if (!injection || typeof injection === 'string') {
next();
Expand Down Expand Up @@ -76,27 +76,37 @@ export const injectIntoHead = (key: string, value: Injection): void => {
};

export const addScript = (key: string, content: string): void => {
if (/_/.test(key)) {
throw new Error('inject.js > addScript - key cannot contain "_" (underscore)');
}

if (!content.trim()) {
injectIntoHead(`${key}.js`, '');
injectIntoHead(key, '');
return;
}
const currentHash = crypto.createHash('sha1').update(content).digest('hex');
injectIntoHead(`${key}.js`, {

injectIntoHead(key, {
type: 'JS',
tag: `<script id="${key}" type="text/javascript" src="${`${getURL(key)}.js?${currentHash}`}"></script>`,
tag: `<script id="${key}" type="text/javascript" src="${`${getURL(key)}_${currentHash}.js`}"></script>`,
content,
});
};

export const addStyle = (key: string, content: string): void => {
if (/_/.test(key)) {
throw new Error('inject.js > addStyle - key cannot contain "_" (underscore)');
}

if (!content.trim()) {
injectIntoHead(`${key}.css`, '');
injectIntoHead(key, '');
return;
}
const currentHash = crypto.createHash('sha1').update(content).digest('hex');
injectIntoHead(`${key}.css`, {

injectIntoHead(key, {
type: 'CSS',
tag: `<link id="${key}" rel="stylesheet" type="text/css" href="${`${getURL(key)}.css?${currentHash}`}">`,
tag: `<link id="${key}" rel="stylesheet" type="text/css" href="${`${getURL(key)}_${currentHash}.css`}">`,
content,
});
};
Expand Down
6 changes: 6 additions & 0 deletions apps/meteor/app/utils/client/getURL.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,19 @@
import { settings } from '../../settings/client';
import { getURLWithoutSettings } from '../lib/getURL';
import { Info } from '../rocketchat.info';

export const getURL = function (
path: string, // eslint-disable-next-line @typescript-eslint/naming-convention
params: Record<string, any> = {},
cloudDeepLinkUrl?: string,
cacheKey?: boolean,
): string {
const cdnPrefix = settings.get('CDN_PREFIX') || '';
const siteUrl = settings.get('Site_Url') || '';

if (cacheKey) {
path += `${path.includes('?') ? '&' : '?'}cacheKey=${Info.version}`;
}

return getURLWithoutSettings(path, params, cdnPrefix, siteUrl, cloudDeepLinkUrl);
};
22 changes: 10 additions & 12 deletions apps/meteor/app/version-check/server/functions/getNewUpdates.ts
Original file line number Diff line number Diff line change
Expand Up @@ -50,18 +50,16 @@ export const getNewUpdates = async () => {
infoUrl: String,
}),
],
alerts: [
Match.Optional([
Match.ObjectIncluding({
id: String,
title: String,
text: String,
textArguments: [Match.Any],
modifiers: [String] as [StringConstructor],
infoUrl: String,
}),
]),
],
alerts: Match.Optional([
Match.ObjectIncluding({
id: String,
title: String,
text: String,
textArguments: [Match.Any],
modifiers: [String] as [StringConstructor],
infoUrl: String,
}),
]),
}),
);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ const GenericUpsellModal = ({
<Modal.Header>
{icon && <Modal.Icon name={icon} />}
<Modal.HeaderText>
<Modal.Tagline color='font-annotation'>{tagline ?? t('Enterprise_capability')}</Modal.Tagline>
<Modal.Tagline color='font-annotation'>{tagline ?? t('Premium_capability')}</Modal.Tagline>
<Modal.Title>{title}</Modal.Title>
</Modal.HeaderText>
<Modal.Close aria-label={t('Close')} onClick={onClose} />
Expand Down
22 changes: 19 additions & 3 deletions apps/meteor/client/hooks/roomActions/useE2EERoomAction.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,15 @@ import { useCallback, useMemo } from 'react';
import { useTranslation } from 'react-i18next';

import { e2e } from '../../../app/e2e/client/rocketchat.e2e';
import { useRoom } from '../../views/room/contexts/RoomContext';
import { dispatchToastMessage } from '../../lib/toast';
import { useRoom, useRoomSubscription } from '../../views/room/contexts/RoomContext';
import type { RoomToolboxActionConfig } from '../../views/room/contexts/RoomToolboxContext';
import { useReactiveValue } from '../useReactiveValue';

export const useE2EERoomAction = () => {
const enabled = useSetting('E2E_Enable', false);
const room = useRoom();
const subscription = useRoomSubscription();
const readyToEncrypt = useReactiveValue(useCallback(() => e2e.isReady(), [])) || room.encrypted;
const permittedToToggleEncryption = usePermission('toggle-room-e2e-encryption', room._id);
const permittedToEditRoom = usePermission('edit-room', room._id);
Expand All @@ -21,8 +23,22 @@ export const useE2EERoomAction = () => {

const toggleE2E = useEndpoint('POST', '/v1/rooms.saveRoomSettings');

const action = useMutableCallback(() => {
void toggleE2E({ rid: room._id, encrypted: !room.encrypted });
const action = useMutableCallback(async () => {
const { success } = await toggleE2E({ rid: room._id, encrypted: !room.encrypted });
if (!success) {
return;
}

dispatchToastMessage({
type: 'success',
message: room.encrypted
? t('E2E_Encryption_disabled_for_room', { roomName: room.name })
: t('E2E_Encryption_enabled_for_room', { roomName: room.name }),
});

if (subscription?.autoTranslate) {
dispatchToastMessage({ type: 'success', message: t('AutoTranslate_Disabled_for_room', { roomName: room.name }) });
}
});

const enabledOnRoom = !!room.encrypted;
Expand Down
Loading

0 comments on commit c7e9a78

Please sign in to comment.