diff --git a/.changeset/new-balloons-speak.md b/.changeset/new-balloons-speak.md new file mode 100644 index 0000000000000..cecaabe353ba7 --- /dev/null +++ b/.changeset/new-balloons-speak.md @@ -0,0 +1,7 @@ +--- +'@rocket.chat/meteor': patch +--- + +Fixed a crash on web client due to service workers not being available, this can happen in multiple scenarios like on Firefox's private window or if the connection is not secure (non-HTTPS), [see more details](https://developer.mozilla.org/en-US/docs/Web/Security/Secure_Contexts). + +Rocket.Chat needs service workers to process E2EE encrypted files on rooms. These types of files won't be available inside private windows, but the rest of E2EE encrypted features should work normally diff --git a/apps/meteor/client/components/message/content/attachments/structure/AttachmentDownloadBase.tsx b/apps/meteor/client/components/message/content/attachments/structure/AttachmentDownloadBase.tsx index 48c078b9146c8..c9adc4533a972 100644 --- a/apps/meteor/client/components/message/content/attachments/structure/AttachmentDownloadBase.tsx +++ b/apps/meteor/client/components/message/content/attachments/structure/AttachmentDownloadBase.tsx @@ -6,18 +6,19 @@ import Action from '../../Action'; type AttachmentDownloadBaseProps = Omit, 'icon'> & { title?: string | undefined; href: string }; -const AttachmentDownloadBase: FC = ({ title, href, ...props }) => { +const AttachmentDownloadBase: FC = ({ title, href, disabled, ...props }) => { const t = useTranslation(); return ( ); diff --git a/apps/meteor/client/hooks/useDownloadFromServiceWorker.ts b/apps/meteor/client/hooks/useDownloadFromServiceWorker.ts index 5ab7f804fec78..199d1507e2847 100644 --- a/apps/meteor/client/hooks/useDownloadFromServiceWorker.ts +++ b/apps/meteor/client/hooks/useDownloadFromServiceWorker.ts @@ -7,13 +7,15 @@ import { downloadAs } from '../lib/download'; const ee = new Emitter>(); -navigator.serviceWorker.addEventListener('message', (event) => { - if (event.data.type === 'attachment-download-result') { - const { result } = event.data as { result: ArrayBuffer; id: string }; +if ('serviceWorker' in navigator) { + navigator.serviceWorker.addEventListener('message', (event) => { + if (event.data.type === 'attachment-download-result') { + const { result } = event.data as { result: ArrayBuffer; id: string }; - ee.emit(event.data.id, { result, id: event.data.id }); - } -}); + ee.emit(event.data.id, { result, id: event.data.id }); + } + }); +} export const registerDownloadForUid = (uid: string, t: ReturnType['t'], title?: string) => { ee.once(uid, ({ result }) => { @@ -23,8 +25,13 @@ export const registerDownloadForUid = (uid: string, t: ReturnType { if (!controller) { - controller = navigator.serviceWorker.controller; + controller = navigator?.serviceWorker?.controller; + } + + if (!controller) { + return; } + controller?.postMessage({ type: 'attachment-download', url: href, @@ -33,7 +40,7 @@ export const forAttachmentDownload = (uid: string, href: string, controller?: Se }; export const useDownloadFromServiceWorker = (href: string, title?: string) => { - const { controller } = navigator.serviceWorker; + const { controller } = navigator?.serviceWorker || {}; const uid = useUniqueId(); diff --git a/apps/meteor/client/views/room/contextualBar/RoomFiles/components/FileItemMenu.tsx b/apps/meteor/client/views/room/contextualBar/RoomFiles/components/FileItemMenu.tsx index 157df8d78027c..4fbf2fc477f11 100644 --- a/apps/meteor/client/views/room/contextualBar/RoomFiles/components/FileItemMenu.tsx +++ b/apps/meteor/client/views/room/contextualBar/RoomFiles/components/FileItemMenu.tsx @@ -17,21 +17,24 @@ type FileItemMenuProps = { const ee = new Emitter>(); -navigator.serviceWorker.addEventListener('message', (event) => { - if (event.data.type === 'attachment-download-result') { - const { result } = event.data as { result: ArrayBuffer; id: string }; +if ('serviceWorker' in navigator) { + navigator.serviceWorker.addEventListener('message', (event) => { + if (event.data.type === 'attachment-download-result') { + const { result } = event.data as { result: ArrayBuffer; id: string }; - ee.emit(event.data.id, { result, id: event.data.id }); - } -}); + ee.emit(event.data.id, { result, id: event.data.id }); + } + }); +} const FileItemMenu = ({ fileData, onClickDelete }: FileItemMenuProps) => { const t = useTranslation(); const room = useRoom(); const userId = useUserId(); const isDeletionAllowed = useMessageDeletionIsAllowed(room._id, fileData, userId); + const canDownloadFile = !fileData.encryption || 'serviceWorker' in navigator; - const { controller } = navigator.serviceWorker; + const { controller } = navigator?.serviceWorker || {}; const uid = useUniqueId(); @@ -53,6 +56,10 @@ const FileItemMenu = ({ fileData, onClickDelete }: FileItemMenuProps) => { ), action: () => { if (fileData.path?.includes('/file-decrypt/')) { + if (!controller) { + return; + } + controller?.postMessage({ type: 'attachment-download', url: fileData.path, @@ -68,6 +75,7 @@ const FileItemMenu = ({ fileData, onClickDelete }: FileItemMenuProps) => { URL.revokeObjectURL(fileData.url); } }, + disabled: !canDownloadFile, }, ...(isDeletionAllowed && onClickDelete && { diff --git a/packages/i18n/src/locales/en.i18n.json b/packages/i18n/src/locales/en.i18n.json index f9f29f1fcc30e..e4d1c611aef66 100644 --- a/packages/i18n/src/locales/en.i18n.json +++ b/packages/i18n/src/locales/en.i18n.json @@ -1756,6 +1756,7 @@ "Dont_ask_me_again_list": "Don't ask me again list", "Download": "Download", "Download_Destkop_App": "Download Desktop App", + "Download_Disabled": "Download disabled", "Download_Info": "Download info", "Download_My_Data": "Download My Data (HTML)", "Download_Pending_Avatars": "Download Pending Avatars",