From d06fb5112994c93a02e53bf9f7f2127aa574f5ab Mon Sep 17 00:00:00 2001 From: yash-rajpal Date: Tue, 16 Dec 2025 17:59:25 +0530 Subject: [PATCH 1/4] chore: refactor iframe external commands to react hooks --- apps/meteor/client/startup/index.ts | 1 - apps/meteor/client/views/root/AppLayout.tsx | 2 + .../root/hooks/useIframeCommands.ts} | 71 +++++++++++-------- 3 files changed, 43 insertions(+), 31 deletions(-) rename apps/meteor/client/{startup/iframeCommands.ts => views/root/hooks/useIframeCommands.ts} (58%) diff --git a/apps/meteor/client/startup/index.ts b/apps/meteor/client/startup/index.ts index 689d5cbe33aa0..ad31ce8030c63 100644 --- a/apps/meteor/client/startup/index.ts +++ b/apps/meteor/client/startup/index.ts @@ -3,7 +3,6 @@ import './appRoot'; import './audit'; import './callbacks'; import './deviceManagement'; -import './iframeCommands'; import './incomingMessages'; import './roles'; import './routes'; diff --git a/apps/meteor/client/views/root/AppLayout.tsx b/apps/meteor/client/views/root/AppLayout.tsx index 33b0714ba3d30..6d44b557a2b31 100644 --- a/apps/meteor/client/views/root/AppLayout.tsx +++ b/apps/meteor/client/views/root/AppLayout.tsx @@ -21,6 +21,7 @@ import { useDesktopTitle } from './hooks/useDesktopTitle'; import { useEmojiOne } from './hooks/useEmojiOne'; import { useEscapeKeyStroke } from './hooks/useEscapeKeyStroke'; import { useGoogleTagManager } from './hooks/useGoogleTagManager'; +import { useIframeCommands } from './hooks/useIframeCommands'; import { useIframeLoginListener } from './hooks/useIframeLoginListener'; import { useLivechatEnterprise } from './hooks/useLivechatEnterprise'; import { useLoadMissedMessages } from './hooks/useLoadMissedMessages'; @@ -71,6 +72,7 @@ const AppLayout = () => { useDesktopFavicon(); useDesktopTitle(); useStartupEvent(); + useIframeCommands(); const layout = useSyncExternalStore(appLayout.subscribe, appLayout.getSnapshot); diff --git a/apps/meteor/client/startup/iframeCommands.ts b/apps/meteor/client/views/root/hooks/useIframeCommands.ts similarity index 58% rename from apps/meteor/client/startup/iframeCommands.ts rename to apps/meteor/client/views/root/hooks/useIframeCommands.ts index 2c5582e2d9d0b..62025c849d35a 100644 --- a/apps/meteor/client/startup/iframeCommands.ts +++ b/apps/meteor/client/views/root/hooks/useIframeCommands.ts @@ -1,17 +1,18 @@ import type { UserStatus, IUser } from '@rocket.chat/core-typings'; import { escapeRegExp } from '@rocket.chat/string-helpers'; -import type { LocationPathname } from '@rocket.chat/ui-contexts'; +import { type LocationPathname, useSetting } from '@rocket.chat/ui-contexts'; import { Meteor } from 'meteor/meteor'; - -import { AccountBox } from '../../app/ui-utils/client/lib/AccountBox'; -import { sdk } from '../../app/utils/client/lib/SDKClient'; -import { afterLogoutCleanUpCallback } from '../../lib/callbacks/afterLogoutCleanUpCallback'; -import { capitalize, ltrim, rtrim } from '../../lib/utils/stringUtils'; -import { baseURI } from '../lib/baseURI'; -import { loginServices } from '../lib/loginServices'; -import { settings } from '../lib/settings'; -import { getUser } from '../lib/user'; -import { router } from '../providers/RouterProvider'; +import { useEffect } from 'react'; + +import { AccountBox } from '../../../../app/ui-utils/client/lib/AccountBox'; +import { sdk } from '../../../../app/utils/client/lib/SDKClient'; +import { afterLogoutCleanUpCallback } from '../../../../lib/callbacks/afterLogoutCleanUpCallback'; +import { capitalize, ltrim, rtrim } from '../../../../lib/utils/stringUtils'; +import { baseURI } from '../../../lib/baseURI'; +import { loginServices } from '../../../lib/loginServices'; +import { settings } from '../../../lib/settings'; +import { getUser } from '../../../lib/user'; +import { router } from '../../../providers/RouterProvider'; const commands = { 'go'(data: { path: string }) { @@ -93,27 +94,37 @@ type CommandMessage[0]; -window.addEventListener('message', (e: MessageEvent) => { - if (!settings.peek('Iframe_Integration_receive_enable')) { - return; - } +export const useIframeCommands = () => { + const iframeReceiveEnabled = useSetting('Iframe_Integration_receive_enable'); + const iframeReceiveOrigin = useSetting('Iframe_Integration_receive_origin', '*'); + + useEffect(() => { + if (!iframeReceiveEnabled) { + return; + } + const messageListener = (event: MessageEvent) => {c + if (typeof event.data !== 'object' || typeof event.data.externalCommand !== 'string') { + return; + } - if (typeof e.data !== 'object' || typeof e.data.externalCommand !== 'string') { - return; - } + if (iframeReceiveOrigin !== '*' && iframeReceiveOrigin.split(',').indexOf(event.origin) === -1) { + console.error('Origin not allowed', event.origin); + return; + } - const origins = settings.peek('Iframe_Integration_receive_origin') ?? '*'; + if (!(event.data.externalCommand in commands)) { + console.error('Command not allowed', event.data.externalCommand); + return; + } - if (origins !== '*' && origins.split(',').indexOf(e.origin) === -1) { - console.error('Origin not allowed', e.origin); - return; - } + const command: (data: any, event: MessageEvent) => void = commands[event.data.externalCommand]; + command(event.data, event); + }; - if (!(e.data.externalCommand in commands)) { - console.error('Command not allowed', e.data.externalCommand); - return; - } + window.addEventListener('message', messageListener); - const command: (data: any, event: MessageEvent) => void = commands[e.data.externalCommand]; - command(e.data, e); -}); + return () => { + window.removeEventListener('message', messageListener); + }; + }, [iframeReceiveEnabled, iframeReceiveOrigin]); +}; From cc77f923e2aa674d5d8f0e087dde852f5e899149 Mon Sep 17 00:00:00 2001 From: yash-rajpal Date: Tue, 16 Dec 2025 18:09:07 +0530 Subject: [PATCH 2/4] add changeset --- .changeset/odd-pigs-hang.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 .changeset/odd-pigs-hang.md diff --git a/.changeset/odd-pigs-hang.md b/.changeset/odd-pigs-hang.md new file mode 100644 index 0000000000000..b3db5fdbdafaf --- /dev/null +++ b/.changeset/odd-pigs-hang.md @@ -0,0 +1,5 @@ +--- +'@rocket.chat/meteor': patch +--- + +Fixes an issue where iframe external commands sent via `window.postMessage` were not being handled correctly when Rocket.Chat was embedded inside an iframe. From 81d6fe38ec1cceffd7a8b3c63bd517dbfcd61bda Mon Sep 17 00:00:00 2001 From: yash-rajpal Date: Tue, 16 Dec 2025 18:19:20 +0530 Subject: [PATCH 3/4] typo --- apps/meteor/client/views/root/hooks/useIframeCommands.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/meteor/client/views/root/hooks/useIframeCommands.ts b/apps/meteor/client/views/root/hooks/useIframeCommands.ts index 62025c849d35a..a7045c2053b76 100644 --- a/apps/meteor/client/views/root/hooks/useIframeCommands.ts +++ b/apps/meteor/client/views/root/hooks/useIframeCommands.ts @@ -102,7 +102,7 @@ export const useIframeCommands = () => { if (!iframeReceiveEnabled) { return; } - const messageListener = (event: MessageEvent) => {c + const messageListener = (event: MessageEvent) => { if (typeof event.data !== 'object' || typeof event.data.externalCommand !== 'string') { return; } From a4c543e8074cee13d2f6f35b244586cdb1f92b7e Mon Sep 17 00:00:00 2001 From: yash-rajpal Date: Fri, 19 Dec 2025 01:25:46 +0530 Subject: [PATCH 4/4] fix review --- apps/meteor/client/views/root/hooks/useIframeCommands.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/meteor/client/views/root/hooks/useIframeCommands.ts b/apps/meteor/client/views/root/hooks/useIframeCommands.ts index a7045c2053b76..a8d0a0ab9ee59 100644 --- a/apps/meteor/client/views/root/hooks/useIframeCommands.ts +++ b/apps/meteor/client/views/root/hooks/useIframeCommands.ts @@ -117,7 +117,7 @@ export const useIframeCommands = () => { return; } - const command: (data: any, event: MessageEvent) => void = commands[event.data.externalCommand]; + const command: (data: MessageEvent['data'], event: MessageEvent) => void = commands[event.data.externalCommand]; command(event.data, event); };