Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 13 additions & 0 deletions .changeset/integration-scripts-no-babel.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
---
'@rocket.chat/meteor': major
---

**Breaking:** Stopped transpiling webhook integration scripts with Babel. Scripts now run as-is inside `isolated-vm` (modern V8).

Class method bodies are now in strict mode per the ES2015 spec. Scripts that relied on sloppy-mode behaviors provided by the previous Babel transpilation must be updated:

- **Implicit globals** — `msg = buildMessage(...)` inside a class method now throws `ReferenceError`. Add `let`, `const`, or `var`.
- **`this` in nested regular functions** — `function helper() { this.JSON.stringify(...) }` now has `this === undefined` instead of `globalThis`. Use arrow functions or pass the dependency explicitly.
- **`arguments.callee`** — Throws `TypeError`. Use a named function expression instead.
- **Octal literals** — `0777` is now a `SyntaxError`. Use `0o777`.
- **Duplicate parameter names** — `function(a, a) {}` is now a `SyntaxError`.
5 changes: 5 additions & 0 deletions .changeset/stale-meals-check.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@rocket.chat/meteor': major
---

Removes insertOrUpdateSound and uploadCustomSound Meteor methods
2 changes: 0 additions & 2 deletions apps/meteor/app/custom-sounds/server/index.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
import './startup/custom-sounds';
import './methods/deleteCustomSound';
import './methods/insertOrUpdateSound';
import './methods/listCustomSounds';
import './methods/uploadCustomSound';
10 changes: 9 additions & 1 deletion apps/meteor/app/custom-sounds/server/lib/insertOrUpdateSound.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,17 @@ import { api } from '@rocket.chat/core-services';
import { CustomSounds } from '@rocket.chat/models';
import { Meteor } from 'meteor/meteor';

import type { ICustomSoundData } from '../methods/insertOrUpdateSound';
import { RocketChatFileCustomSoundsInstance } from '../startup/custom-sounds';

export type ICustomSoundData = {
_id?: string;
name: string;
extension: string;
previousName?: string;
previousExtension?: string;
newFile?: boolean;
};

export const insertOrUpdateSound = async (soundData: ICustomSoundData): Promise<string> => {
// silently strip colon; this allows for uploading :soundname: as soundname
soundData.name = (soundData.name || '').replace(/:/g, '');
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import { api } from '@rocket.chat/core-services';
import type { RequiredField } from '@rocket.chat/core-typings';

import type { ICustomSoundData } from './insertOrUpdateSound';
import { RocketChatFile } from '../../../file/server';
import type { ICustomSoundData } from '../methods/insertOrUpdateSound';
import { RocketChatFileCustomSoundsInstance } from '../startup/custom-sounds';

export const uploadCustomSound = async (
Expand Down

This file was deleted.

26 changes: 0 additions & 26 deletions apps/meteor/app/custom-sounds/server/methods/uploadCustomSound.ts

This file was deleted.

23 changes: 0 additions & 23 deletions apps/meteor/app/file-upload/server/methods/sendFileMessage.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ import type {
IMessage,
FileProp,
} from '@rocket.chat/core-typings';
import type { ServerMethods } from '@rocket.chat/ddp-client';
import { Rooms, Uploads, Users } from '@rocket.chat/models';
import { Match, check } from 'meteor/check';
import { Meteor } from 'meteor/meteor';
Expand All @@ -18,7 +17,6 @@ import { getFileExtension } from '../../../../lib/utils/getFileExtension';
import { callbacks } from '../../../../server/lib/callbacks';
import { SystemLogger } from '../../../../server/lib/logger/system';
import { canAccessRoomAsync } from '../../../authorization/server/functions/canAccessRoom';
import { methodDeprecationLogger } from '../../../lib/server/lib/deprecationWarningLogger';
import { executeSendMessage } from '../../../lib/server/methods/sendMessage';
import { FileUpload } from '../lib/FileUpload';

Expand Down Expand Up @@ -163,13 +161,6 @@ export const parseFileIntoMessageAttachments = async (
return { files, attachments };
};

declare module '@rocket.chat/ddp-client' {
// eslint-disable-next-line @typescript-eslint/naming-convention
interface ServerMethods {
sendFileMessage: (roomId: string, _store: string, file: Partial<IUpload>, msgData?: Record<string, any>) => boolean;
}
}

export const sendFileMessage = async (
userId: string,
{
Expand Down Expand Up @@ -239,17 +230,3 @@ export const sendFileMessage = async (

return msg;
};

Meteor.methods<ServerMethods>({
async sendFileMessage(roomId, _store, file, msgData = {}) {
methodDeprecationLogger.method('sendFileMessage', '9.0.0', '/v1/rooms.mediaConfirm/:rid/:fileId');
const userId = Meteor.userId();
if (!userId) {
throw new Meteor.Error('error-invalid-user', 'Invalid user', {
method: 'sendFileMessage',
} as any);
}

return sendFileMessage(userId, { roomId, file, msgData });
},
});
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@ import { Subscriptions, Users, Rooms } from '@rocket.chat/models';
import { Match } from 'meteor/check';
import { Meteor } from 'meteor/meteor';

import { compileIntegrationScript } from './compileIntegrationScript';
import { isScriptEngineFrozen } from './validateScriptEngine';
import { validateScriptSyntax } from './validateScriptSyntax';
import { parseCSV } from '../../../../lib/utils/parseCSV';
import { hasPermissionAsync, hasAllPermissionAsync } from '../../../authorization/server/functions/hasPermission';
import { outgoingEvents } from '../../lib/outgoingEvents';
Expand Down Expand Up @@ -181,7 +181,9 @@ export const validateOutgoingIntegration = async function (
integration.script &&
integration.script.trim() !== ''
) {
const { script, error } = compileIntegrationScript(integration.script, { transpile: !skipTranspile });
// isolated-vm embeds modern V8 and runs the script natively, so no
// transpilation is needed. Syntax is still validated at save time.
const { script, error } = validateScriptSyntax(integration.script);
integrationData.scriptCompiled = script;
integrationData.scriptError = error;
}
Expand Down
37 changes: 37 additions & 0 deletions apps/meteor/app/integrations/server/lib/validateScriptSyntax.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
import vm from 'node:vm';

/**
* Validate the syntax of a user-supplied integration script and return it
* as-is for storage in `scriptCompiled`.
*
* Integration scripts run inside `isolated-vm`, which embeds modern V8 and
* handles ES2023+ natively. Transpilation via Babel is no longer performed.
*
* ⚠️ **Breaking change (9.0.0):** Class method bodies are now in strict
* mode per the ES2015 spec. Scripts that relied on sloppy-mode behaviors
* (e.g. implicit globals, `arguments.callee`, `this === globalThis` inside
* regular nested functions) must be updated. See the migration guide in the
* PR description.
*
* Returns `{ script }` on success or `{ error }` when the input has a
* syntax error. `error` has the same `{ name, message, stack }` shape the
* previous flow persisted in `scriptError`.
*/
export function validateScriptSyntax(
script: string,
): { script: string; error?: undefined } | { script?: undefined; error: Pick<Error, 'name' | 'message' | 'stack'> } {
try {
// Wrap so top-level return/declarations parse the same way as in
// getCompatibilityScript at runtime. vm.Script only parses — it does
// not execute the code here.
// eslint-disable-next-line no-new
new vm.Script(`(function(){${script}})`);
return { script };
} catch (e) {
if (e instanceof SyntaxError) {
const { name, message, stack } = e;
return { error: { name, message, stack } };
}
throw e;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,8 @@ import { Meteor } from 'meteor/meteor';
import { addUserRolesAsync } from '../../../../../server/lib/roles/addUserRoles';
import { hasPermissionAsync, hasAllPermissionAsync } from '../../../../authorization/server/functions/hasPermission';
import { notifyOnIntegrationChanged } from '../../../../lib/server/lib/notifyListener';
import { compileIntegrationScript } from '../../lib/compileIntegrationScript';
import { validateScriptEngine, isScriptEngineFrozen } from '../../lib/validateScriptEngine';
import { validateScriptSyntax } from '../../lib/validateScriptSyntax';

const validChannelChars = ['@', '#'];

Expand Down Expand Up @@ -107,13 +107,16 @@ export const addIncomingIntegration = async (userId: string, integration: INewIn
_createdBy: await Users.findOne({ _id: userId }, { projection: { username: 1 } }),
};

// Validate the script syntax if it is enabled and using a sandbox that is
// not frozen. isolated-vm embeds modern V8 and runs the script natively, so
// no transpilation is needed.
if (
!isScriptEngineFrozen(integrationData.scriptEngine) &&
integration.scriptEnabled === true &&
integration.script &&
integration.script.trim() !== ''
) {
const { script, error } = compileIntegrationScript(integration.script, { transpile: !skipTranspile });
const { script, error } = validateScriptSyntax(integration.script);
if (error) {
integrationData.scriptCompiled = undefined;
integrationData.scriptError = error;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,8 @@ import { Meteor } from 'meteor/meteor';
import { addUserRolesAsync } from '../../../../../server/lib/roles/addUserRoles';
import { hasAllPermissionAsync, hasPermissionAsync } from '../../../../authorization/server/functions/hasPermission';
import { notifyOnIntegrationChanged } from '../../../../lib/server/lib/notifyListener';
import { compileIntegrationScript } from '../../lib/compileIntegrationScript';
import { isScriptEngineFrozen, validateScriptEngine } from '../../lib/validateScriptEngine';
import { validateScriptSyntax } from '../../lib/validateScriptSyntax';

const validChannelChars = ['@', '#'];

Expand Down Expand Up @@ -83,25 +83,23 @@ export const updateIncomingIntegration = async (

const isFrozen = isScriptEngineFrozen(scriptEngine);

// Default to transpiling with Babel for backwards compatibility; integrations
// can opt-out per-record by setting `skipTranspile: true` (removed in 9.0.0).
const skipTranspile = integration.skipTranspile === true;

if (!isFrozen && integration.scriptEnabled === true && integration.script && integration.script.trim() !== '') {
const { script, error } = compileIntegrationScript(integration.script, { transpile: !skipTranspile });
// isolated-vm embeds modern V8 and runs the script natively, so no
// transpilation is needed. Syntax is still validated at save time.
const { script, error } = validateScriptSyntax(integration.script);
if (error) {
await Integrations.updateOne(
{ _id: integrationId },
{
$set: { scriptError: error, skipTranspile },
$set: { scriptError: error },
$unset: { scriptCompiled: 1 as const },
},
);
} else {
await Integrations.updateOne(
{ _id: integrationId },
{
$set: { scriptCompiled: script, skipTranspile },
$set: { scriptCompiled: script },
$unset: { scriptError: 1 as const },
},
);
Expand Down Expand Up @@ -170,7 +168,6 @@ export const updateIncomingIntegration = async (
...(typeof integration.script !== 'undefined' && { script: integration.script }),
scriptEnabled: integration.scriptEnabled,
...(scriptEngine && { scriptEngine }),
skipTranspile,
}),
...(typeof integration.overrideDestinationChannelEnabled !== 'undefined' && {
overrideDestinationChannelEnabled: integration.overrideDestinationChannelEnabled,
Expand Down
2 changes: 1 addition & 1 deletion apps/meteor/app/utils/rocketchat.info
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
{
"version": "8.5.0-develop"
"version": "9.0.0-develop"
}
4 changes: 1 addition & 3 deletions apps/meteor/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@rocket.chat/meteor",
"version": "8.5.0-develop",
"version": "9.0.0-develop",
"private": true,
"description": "The Ultimate Open Source WebChat Platform",
"keywords": [
Expand Down Expand Up @@ -68,8 +68,6 @@
"@aws-sdk/client-s3": "^3.862.0",
"@aws-sdk/lib-storage": "^3.862.0",
"@aws-sdk/s3-request-presigner": "^3.862.0",
"@babel/core": "~7.29.0",
"@babel/preset-env": "~7.29.5",
"@babel/runtime": "~7.29.2",
"@bugsnag/js": "~7.20.2",
"@bugsnag/plugin-react": "~7.19.0",
Expand Down
Loading
Loading