diff --git a/.eslintrc.js b/.eslintrc.js index f4d92f1cf2..dd406134fe 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -266,6 +266,9 @@ module.exports = { parserOptions: { project: ["./playwright/tsconfig.json"], }, + rules: { + "react-hooks/rules-of-hooks": ["off"], + }, }, ], settings: { diff --git a/.github/workflows/release_prepare.yml b/.github/workflows/release_prepare.yml index ce088a9327..5fb969a1c6 100644 --- a/.github/workflows/release_prepare.yml +++ b/.github/workflows/release_prepare.yml @@ -20,6 +20,9 @@ on: jobs: prepare: runs-on: ubuntu-24.04 + env: + # The order is specified bottom-up to avoid any races for allchange + REPOS: matrix-js-sdk element-web element-desktop steps: - name: Checkout Element Desktop uses: actions/checkout@v4 diff --git a/.node-version b/.node-version index 209e3ef4b6..2bd5a0a98a 100644 --- a/.node-version +++ b/.node-version @@ -1 +1 @@ -20 +22 diff --git a/Dockerfile b/Dockerfile index 3f3b9a1d71..908c05520c 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,5 +1,5 @@ # Builder -FROM --platform=$BUILDPLATFORM node:20-bullseye as builder +FROM --platform=$BUILDPLATFORM node:22-bullseye as builder # Support custom branch of the js-sdk. This also helps us build images of element-web develop. ARG USE_CUSTOM_SDKS=false diff --git a/docs/theming.md b/docs/theming.md index 9d3d67e68d..100baeca71 100644 --- a/docs/theming.md +++ b/docs/theming.md @@ -29,7 +29,7 @@ default theme, you would use `default_theme: "custom-Electric Blue"`. e.g. in config.json: -``` +```json5 "setting_defaults": { "custom_themes": [ { @@ -59,6 +59,10 @@ e.g. in config.json: "timeline-text-color": "#2e2f32", "timeline-text-secondary-color": "#61708b", "timeline-highlights-color": "#f3f8fd", + + // These should both be 8 values long + "username-colors": ["#ff0000", /*...*/], + "avatar-background-colors": ["#cc0000", /*...*/] }, "compound": { "--cpd-color-icon-accent-tertiary": "var(--cpd-color-blue-800)", diff --git a/element.io/app/config.json b/element.io/app/config.json index 4dcc75aeeb..771df35091 100644 --- a/element.io/app/config.json +++ b/element.io/app/config.json @@ -46,5 +46,13 @@ "map_style_url": "https://api.maptiler.com/maps/streets/style.json?key=fU3vlMsMn4Jb6dnEIFsx", "setting_defaults": { "RustCrypto.staged_rollout_percent": 60 + }, + "features": { + "feature_video_rooms": true, + "feature_group_calls": true, + "feature_element_call_video_rooms": true + }, + "element_call": { + "url": "https://call.element.io" } } diff --git a/package.json b/package.json index 4ab26bb1df..11232c479c 100644 --- a/package.json +++ b/package.json @@ -84,7 +84,7 @@ "dependencies": { "@babel/runtime": "^7.12.5", "@formatjs/intl-segmenter": "^11.5.7", - "@matrix-org/analytics-events": "^0.26.0", + "@matrix-org/analytics-events": "^0.28.0", "@matrix-org/emojibase-bindings": "^1.3.3", "@vector-im/matrix-wysiwyg": "2.37.13", "@matrix-org/react-sdk-module-api": "^2.4.0", @@ -148,7 +148,7 @@ "tar-js": "^0.3.0", "temporal-polyfill": "^0.2.5", "ua-parser-js": "^1.0.2", - "uuid": "^10.0.0", + "uuid": "^11.0.0", "what-input": "^5.2.10" }, "devDependencies": { @@ -208,7 +208,7 @@ "@types/qrcode": "^1.3.5", "@types/react": "18.3.3", "@types/react-beautiful-dnd": "^13.0.0", - "@types/react-dom": "18.3.0", + "@types/react-dom": "18.3.1", "@types/react-transition-group": "^4.4.0", "@types/sanitize-html": "2.13.0", "@types/sdp-transform": "^2.4.6", @@ -219,7 +219,7 @@ "@types/uuid": "^10.0.0", "@typescript-eslint/eslint-plugin": "^8.0.0", "@typescript-eslint/parser": "^8.0.0", - "axe-core": "4.10.0", + "axe-core": "4.10.2", "babel-jest": "^29.0.0", "babel-loader": "^9.0.0", "babel-plugin-jsx-remove-data-test-id": "^3.0.0", @@ -242,7 +242,7 @@ "eslint-plugin-jsx-a11y": "^6.5.1", "eslint-plugin-matrix-org": "^2.0.2", "eslint-plugin-react": "^7.28.0", - "eslint-plugin-react-hooks": "^4.3.0", + "eslint-plugin-react-hooks": "^5.0.0", "eslint-plugin-unicorn": "^56.0.0", "express": "^4.18.2", "fake-indexeddb": "^6.0.0", diff --git a/playwright/Dockerfile b/playwright/Dockerfile index cbce8f0d00..9d478ff231 100644 --- a/playwright/Dockerfile +++ b/playwright/Dockerfile @@ -1,4 +1,4 @@ -FROM mcr.microsoft.com/playwright:v1.48.0-jammy +FROM mcr.microsoft.com/playwright:v1.48.2-jammy WORKDIR /work diff --git a/playwright/e2e/pinned-messages/index.ts b/playwright/e2e/pinned-messages/index.ts index e5d08a75b7..ac50b62294 100644 --- a/playwright/e2e/pinned-messages/index.ts +++ b/playwright/e2e/pinned-messages/index.ts @@ -196,14 +196,7 @@ export class Helpers { */ async assertEmptyPinnedMessagesList() { const rightPanel = this.getRightPanel(); - await expect(rightPanel).toMatchScreenshot(`pinned-messages-list-empty.png`, { - // hide the tooltip "Room information" to avoid flakiness - css: ` - [data-floating-ui-portal] { - display: none !important; - } - `, - }); + await expect(rightPanel).toMatchScreenshot(`pinned-messages-list-empty.png`); } /** diff --git a/playwright/e2e/release-announcement/index.ts b/playwright/e2e/release-announcement/index.ts index 81146be70e..59db80c3c6 100644 --- a/playwright/e2e/release-announcement/index.ts +++ b/playwright/e2e/release-announcement/index.ts @@ -42,7 +42,7 @@ export class Helpers { */ async assertReleaseAnnouncementIsVisible(name: string) { await expect(this.getReleaseAnnouncement(name)).toBeVisible(); - await expect(this.page).toMatchScreenshot(`release-announcement-${name}.png`); + await expect(this.page).toMatchScreenshot(`release-announcement-${name}.png`, { showTooltips: true }); } /** diff --git a/playwright/element-web-test.ts b/playwright/element-web-test.ts index 93b119ee7a..8d5229a510 100644 --- a/playwright/element-web-test.ts +++ b/playwright/element-web-test.ts @@ -345,6 +345,7 @@ export const expect = baseExpect.extend({ if (!options?.showTooltips) { css += ` + [data-floating-ui-portal], [role="tooltip"] { visibility: hidden !important; } diff --git a/playwright/plugins/homeserver/synapse/index.ts b/playwright/plugins/homeserver/synapse/index.ts index fcab09569c..5a04da3e46 100644 --- a/playwright/plugins/homeserver/synapse/index.ts +++ b/playwright/plugins/homeserver/synapse/index.ts @@ -20,7 +20,7 @@ import { randB64Bytes } from "../../utils/rand"; // Docker tag to use for synapse docker image. // We target a specific digest as every now and then a Synapse update will break our CI. // This digest is updated by the playwright-image-updates.yaml workflow periodically. -const DOCKER_TAG = "develop@sha256:85dc2cf25f45ee91fd87efa0ddf2220a5933d212ed656886d5f3832ae3a9ddaf"; +const DOCKER_TAG = "develop@sha256:47ed20bdf698523c1876aded101ffa5cd5c5b879c80762b7b18b87347349123b"; async function cfgDirFromTemplate(opts: StartHomeserverOpts): Promise> { const templateDir = path.join(__dirname, "templates", opts.template); diff --git a/playwright/snapshots/chat-export/html-export.spec.ts/html-export-linux.png b/playwright/snapshots/chat-export/html-export.spec.ts/html-export-linux.png index 6a490c2157..8519e162f2 100644 Binary files a/playwright/snapshots/chat-export/html-export.spec.ts/html-export-linux.png and b/playwright/snapshots/chat-export/html-export.spec.ts/html-export-linux.png differ diff --git a/playwright/snapshots/settings/preferences-user-settings-tab.spec.ts/Preferences-user-settings-tab-should-be-rendered-properly-1-linux.png b/playwright/snapshots/settings/preferences-user-settings-tab.spec.ts/Preferences-user-settings-tab-should-be-rendered-properly-1-linux.png index 81c08756df..31a7ed42f1 100644 Binary files a/playwright/snapshots/settings/preferences-user-settings-tab.spec.ts/Preferences-user-settings-tab-should-be-rendered-properly-1-linux.png and b/playwright/snapshots/settings/preferences-user-settings-tab.spec.ts/Preferences-user-settings-tab-should-be-rendered-properly-1-linux.png differ diff --git a/playwright/snapshots/threads/threads.spec.ts/Reply-to-the-location-on-ThreadView-linux.png b/playwright/snapshots/threads/threads.spec.ts/Reply-to-the-location-on-ThreadView-linux.png index e7f09c67fb..f5eb3935ba 100644 Binary files a/playwright/snapshots/threads/threads.spec.ts/Reply-to-the-location-on-ThreadView-linux.png and b/playwright/snapshots/threads/threads.spec.ts/Reply-to-the-location-on-ThreadView-linux.png differ diff --git a/res/css/_components.pcss b/res/css/_components.pcss index 15dededcd3..d296760712 100644 --- a/res/css/_components.pcss +++ b/res/css/_components.pcss @@ -287,7 +287,6 @@ @import "./views/rooms/_HistoryTile.pcss"; @import "./views/rooms/_IRCLayout.pcss"; @import "./views/rooms/_JumpToBottomButton.pcss"; -@import "./views/rooms/_LegacyRoomHeader.pcss"; @import "./views/rooms/_LinkPreviewGroup.pcss"; @import "./views/rooms/_LinkPreviewWidget.pcss"; @import "./views/rooms/_LiveContentSummary.pcss"; diff --git a/res/css/structures/_RoomView.pcss b/res/css/structures/_RoomView.pcss index 52fa523c4e..359f67c803 100644 --- a/res/css/structures/_RoomView.pcss +++ b/res/css/structures/_RoomView.pcss @@ -181,11 +181,6 @@ Please see LICENSE files in the repository root for full details. } } -/* Rooms with immersive content */ -.mx_RoomView_immersive .mx_LegacyRoomHeader_wrapper { - border: unset; -} - .mx_RoomView_inCall { .mx_RoomView_statusAreaBox_line { margin-top: 2px; diff --git a/res/css/views/elements/_EditableItemList.pcss b/res/css/views/elements/_EditableItemList.pcss index 34ec3199b4..8a85f615d8 100644 --- a/res/css/views/elements/_EditableItemList.pcss +++ b/res/css/views/elements/_EditableItemList.pcss @@ -18,10 +18,9 @@ Please see LICENSE files in the repository root for full details. .mx_EditableItem_delete { @mixin customisedCancelButton; order: 3; - margin-right: 5px; vertical-align: middle; - width: 14px; - height: 14px; + width: 28px; + height: 28px; background-color: $alert; mask-size: 100%; } @@ -42,7 +41,7 @@ Please see LICENSE files in the repository root for full details. .mx_EditableItem_item { flex: auto 1 0; order: 1; - width: calc(100% - 14px); /* leave space for the remove button */ + width: calc(100% - 28px); /* leave space for the remove button */ overflow-x: hidden; text-overflow: ellipsis; } diff --git a/res/css/views/rooms/_LegacyRoomHeader.pcss b/res/css/views/rooms/_LegacyRoomHeader.pcss deleted file mode 100644 index dc41108041..0000000000 --- a/res/css/views/rooms/_LegacyRoomHeader.pcss +++ /dev/null @@ -1,281 +0,0 @@ -/* -Copyright 2024 New Vector Ltd. -Copyright 2023 The Matrix.org Foundation C.I.C. -Copyright 2015, 2016 OpenMarket Ltd - -SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only -Please see LICENSE files in the repository root for full details. -*/ - -:root { - --RoomHeader-indicator-dot-size: 8px; - --RoomHeader-indicator-dot-offset: -3px; - --RoomHeader-indicator-pulseColor: $alert; -} - -.mx_LegacyRoomHeader { - flex: 0 0 50px; - border-bottom: 1px solid $primary-hairline-color; - background-color: $background; - - .mx_LegacyRoomHeader_icon { - height: 12px; - width: 12px; - - &.mx_LegacyRoomHeader_icon_video { - height: 14px; - width: 14px; - background-color: $secondary-content; - mask-image: url("$(res)/img/element-icons/call/video-call.svg"); - mask-size: 100%; - } - - &.mx_E2EIcon { - margin: 0; - height: 100%; /* To give the tooltip room to breathe */ - } - } - - .mx_CallDuration { - margin-top: calc(($font-15px - $font-13px) / 2); /* To align with the name */ - font-size: $font-13px; - } -} - -.mx_LegacyRoomHeader_wrapper { - height: 44px; - display: flex; - align-items: center; - min-width: 0; - padding: 10px 20px 9px 16px; - border-bottom: 1px solid $separator; - - .mx_InviteOnlyIcon_large { - margin: 0; - } - - .mx_BetaCard_betaPill { - margin-right: $spacing-8; - } - - /* The container of E2EIcon in the legacy header needs to have its height set */ - & > span { - height: 100%; - } -} - -.mx_LegacyRoomHeader_name { - flex: 0 1 auto; - overflow: hidden; - color: $primary-content; - font: var(--cpd-font-heading-sm-semibold); - font-weight: var(--cpd-font-weight-semibold); - min-height: 24px; - align-items: center; - border-radius: 6px; - margin: 0 3px; - padding: 1px 4px; - display: flex; - user-select: none; - cursor: pointer; - - &:hover { - background-color: $quinary-content; - } - - .mx_LegacyRoomHeader_nametext { - white-space: nowrap; - text-overflow: ellipsis; - overflow: hidden; - } - - .mx_LegacyRoomHeader_chevron { - align-self: center; - width: 20px; - height: 20px; - mask-position: center; - mask-size: 20px; - mask-repeat: no-repeat; - mask-image: url("$(res)/img/feather-customised/chevron-down.svg"); - background-color: $tertiary-content; - } - - &.mx_LegacyRoomHeader_name--textonly { - cursor: unset; - - &:hover { - background-color: unset; - } - } - - &[aria-expanded="true"] { - background-color: $separator; - - .mx_LegacyRoomHeader_chevron { - transform: rotate(180deg); - } - } -} - -.mx_LegacyRoomHeader_settingsHint { - color: $settings-grey-fg-color !important; -} - -.mx_LegacyRoomHeader_searchStatus { - font-weight: normal; - opacity: 0.6; -} - -.mx_RoomTopic { - position: relative; - cursor: pointer; -} - -.mx_LegacyRoomHeader_topic { - $lines: 2; - - flex: 1; - color: $secondary-content; - font: var(--cpd-font-body-sm-regular); - line-height: 1rem; - max-height: calc(1rem * $lines); - - overflow: hidden; - -webkit-line-clamp: $lines; /* See: https://drafts.csswg.org/css-overflow-3/#webkit-line-clamp */ - -webkit-box-orient: vertical; - display: -webkit-box; -} - -.mx_LegacyRoomHeader_topic .mx_Emoji { - /* Undo font size increase to prevent vertical cropping and ensure the same size */ - /* as in plain text emojis */ - font-size: inherit; -} - -.mx_LegacyRoomHeader_avatar { - flex: 0; - margin: 0 7px; - position: relative; - cursor: pointer; -} - -.mx_LegacyRoomHeader_button_unreadIndicator_bg { - position: absolute; - right: var(--RoomHeader-indicator-dot-offset); - top: var(--RoomHeader-indicator-dot-offset); - margin: 4px; - width: var(--RoomHeader-indicator-dot-size); - height: var(--RoomHeader-indicator-dot-size); - border-radius: 50%; - transform: scale(1.6); - transform-origin: center center; - background: $background; -} - -.mx_LegacyRoomHeader_button_unreadIndicator { - position: absolute; - right: var(--RoomHeader-indicator-dot-offset); - top: var(--RoomHeader-indicator-dot-offset); - margin: 4px; - - &.mx_Indicator_highlight { - background: var(--cpd-color-icon-critical-primary); - box-shadow: var(--cpd-color-icon-critical-primary); - } - - &.mx_Indicator_notification { - background: var(--cpd-color-icon-success-primary); - box-shadow: var(--cpd-color-icon-success-primary); - } - - &.mx_Indicator_activity { - background: var(--cpd-color-icon-primary); - box-shadow: var(--cpd-color-icon-primary); - } -} - -.mx_LegacyRoomHeader_forgetButton::before { - mask-image: url("$(res)/img/element-icons/leave.svg"); - width: 26px; -} - -.mx_LegacyRoomHeader_appsButton::before { - mask-image: url("$(res)/img/element-icons/room/apps.svg"); -} - -.mx_LegacyRoomHeader_appsButton_highlight::before { - background-color: $accent; -} - -.mx_LegacyRoomHeader_searchButton::before { - mask-image: url("$(res)/img/element-icons/room/search-inset.svg"); -} - -.mx_LegacyRoomHeader_inviteButton::before { - mask-image: url("$(res)/img/element-icons/room/invite.svg"); -} - -.mx_LegacyRoomHeader_voiceCallButton::before { - mask-image: url("$(res)/img/element-icons/call/voice-call.svg"); - - /* The call button SVG is padded slightly differently, so match it up to the size */ - /* of the other icons */ - mask-size: 20px; - mask-position: center; -} - -.mx_LegacyRoomHeader_videoCallButton::before { - mask-image: url("$(res)/img/element-icons/call/video-call.svg"); -} - -.mx_LegacyRoomHeader_layoutButton--freedom::before, -.mx_LegacyRoomHeader_freedomIcon::before { - mask-image: url("$(res)/img/element-icons/call/freedom.svg"); -} - -.mx_LegacyRoomHeader_layoutButton--spotlight::before, -.mx_LegacyRoomHeader_spotlightIcon::before { - mask-image: url("$(res)/img/element-icons/call/spotlight.svg"); -} - -.mx_LegacyRoomHeader_closeButton { - &::before { - mask-image: url("@vector-im/compound-design-tokens/icons/close.svg"); - mask-size: 20px; - mask-position: center; - } - - &:hover { - background: unset; /* remove background color on hover */ - - &::before { - background-color: $icon-button-color; /* set the default background color */ - } - } -} - -.mx_LegacyRoomHeader_minimiseButton::before { - mask-image: url("$(res)/img/element-icons/reduce.svg"); -} - -.mx_LegacyRoomHeader_layoutMenu .mx_IconizedContextMenu_icon::before { - content: ""; - width: 16px; - height: 16px; - display: block; - mask-position: center; - mask-size: 20px; - mask-repeat: no-repeat; - background: $primary-content; -} - -@media only screen and (max-width: 480px) { - .mx_LegacyRoomHeader_wrapper { - padding: 0; - margin: 0; - } - - .mx_LegacyRoomHeader { - overflow: hidden; - } -} diff --git a/res/css/views/rooms/_RoomHeader.pcss b/res/css/views/rooms/_RoomHeader.pcss index 16bf45435a..a53d06fd1c 100644 --- a/res/css/views/rooms/_RoomHeader.pcss +++ b/res/css/views/rooms/_RoomHeader.pcss @@ -88,3 +88,8 @@ Please see LICENSE files in the repository root for full details. .mx_RoomHeader .mx_BaseAvatar { flex-shrink: 0; } + +.mx_RoomHeader_videoCallOption { + /* Workaround for https://github.com/element-hq/compound/issues/331 */ + min-width: 240px; +} diff --git a/res/img/camera.svg b/res/img/camera.svg deleted file mode 100644 index 6519496f78..0000000000 --- a/res/img/camera.svg +++ /dev/null @@ -1,12 +0,0 @@ - - - - icon_camera - Created with Sketch. - - - - - - - diff --git a/res/img/element-icons/call/freedom.svg b/res/img/element-icons/call/freedom.svg deleted file mode 100644 index 0a883b7833..0000000000 --- a/res/img/element-icons/call/freedom.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/res/img/element-icons/call/spotlight.svg b/res/img/element-icons/call/spotlight.svg deleted file mode 100644 index f9d96a1e85..0000000000 --- a/res/img/element-icons/call/spotlight.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/res/img/element-icons/reduce.svg b/res/img/element-icons/reduce.svg deleted file mode 100644 index 3179e33a23..0000000000 --- a/res/img/element-icons/reduce.svg +++ /dev/null @@ -1,4 +0,0 @@ - - - - diff --git a/res/img/feather-customised/edit.svg b/res/img/feather-customised/edit.svg deleted file mode 100644 index f511aa1477..0000000000 --- a/res/img/feather-customised/edit.svg +++ /dev/null @@ -1,4 +0,0 @@ - - - - diff --git a/res/img/location/pointer.svg b/res/img/location/pointer.svg deleted file mode 100644 index 8a7c5edf71..0000000000 --- a/res/img/location/pointer.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/res/img/markdown.svg b/res/img/markdown.svg deleted file mode 100644 index 9aadd3cb7f..0000000000 --- a/res/img/markdown.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/res/img/voip/signal-bars.svg b/res/img/voip/signal-bars.svg deleted file mode 100644 index 6802ba2d34..0000000000 --- a/res/img/voip/signal-bars.svg +++ /dev/null @@ -1,5 +0,0 @@ - - - - - diff --git a/res/jitsi_external_api.min.js b/res/jitsi_external_api.min.js index 880aec5b21..2bbee8305f 100644 --- a/res/jitsi_external_api.min.js +++ b/res/jitsi_external_api.min.js @@ -1,2 +1,2 @@ -!function(e,t){"object"==typeof exports&&"object"==typeof module?module.exports=t():"function"==typeof define&&define.amd?define([],t):"object"==typeof exports?exports.JitsiMeetExternalAPI=t():e.JitsiMeetExternalAPI=t()}(self,(()=>(()=>{var e={372:(e,t,n)=>{"use strict";n.d(t,{default:()=>N});var r=n(620),i=n.n(r);class s extends r{constructor(){var e,t,n;super(...arguments),e=this,n={},(t=function(e){var t=function(e,t){if("object"!=typeof e||null===e)return e;var n=e[Symbol.toPrimitive];if(void 0!==n){var r=n.call(e,t);if("object"!=typeof r)return r;throw new TypeError("@@toPrimitive must return a primitive value.")}return String(e)}(e,"string");return"symbol"==typeof t?t:String(t)}(t="_storage"))in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n}clear(){this._storage={}}get length(){return Object.keys(this._storage).length}getItem(e){return this._storage[e]}setItem(e,t){this._storage[e]=t}removeItem(e){delete this._storage[e]}key(e){const t=Object.keys(this._storage);if(!(t.length<=e))return t[e]}serialize(){let e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:[];if(0===e.length)return JSON.stringify(this._storage);const t={...this._storage};return e.forEach((e=>{delete t[e]})),JSON.stringify(t)}}const o=new class extends r{constructor(){super();try{this._storage=window.localStorage,this._localStorageDisabled=!1}catch(e){}this._storage||(console.warn("Local storage is disabled."),this._storage=new s,this._localStorageDisabled=!0)}isLocalStorageDisabled(){return this._localStorageDisabled}setLocalStorageDisabled(e){this._localStorageDisabled=e;try{this._storage=e?new s:window.localStorage}catch(e){}this._storage||(this._storage=new s)}clear(){this._storage.clear(),this.emit("changed")}get length(){return this._storage.length}getItem(e){return this._storage.getItem(e)}setItem(e,t){let n=arguments.length>2&&void 0!==arguments[2]&&arguments[2];this._storage.setItem(e,t),n||this.emit("changed")}removeItem(e){this._storage.removeItem(e),this.emit("changed")}key(e){return this._storage.key(e)}serialize(){let e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:[];if(this.isLocalStorageDisabled())return this._storage.serialize(e);const t=this._storage.length,n={};for(let r=0;r0&&void 0!==arguments[0]?arguments[0]:{};this.postis=function(e){var t,n=e.scope,r=e.window,i=e.windowForEventListening||window,s=e.allowedOrigin,o={},a=[],d={},l=!1,u="__ready__",p=function(e){var t;try{t=c(e.data)}catch(e){return}if((!s||e.origin===s)&&t&&t.postis&&t.scope===n){var r=o[t.method];if(r)for(var i=0;i{},this.postis.listen(v,(e=>this._receiveCallback(e)))}dispose(){this.postis.destroy()}send(e){this.postis.send({method:v,params:e})}setReceiveCallback(e){this._receiveCallback=e}}const _="request",b="response";class w{constructor(){let{backend:e}=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{};this._listeners=new Map,this._requestID=0,this._responseHandlers=new Map,this._unprocessedMessages=new Set,this.addListener=this.on,e&&this.setBackend(e)}_disposeBackend(){this._backend&&(this._backend.dispose(),this._backend=null)}_onMessageReceived(e){if(e.type===b){const t=this._responseHandlers.get(e.id);t&&(t(e),this._responseHandlers.delete(e.id))}else e.type===_?this.emit("request",e.data,((t,n)=>{this._backend.send({type:b,error:n,id:e.id,result:t})})):this.emit("event",e.data)}dispose(){this._responseHandlers.clear(),this._unprocessedMessages.clear(),this.removeAllListeners(),this._disposeBackend()}emit(e){for(var t=arguments.length,n=new Array(t>1?t-1:0),r=1;r{s=e(...n)||s})),s||this._unprocessedMessages.add(n),s}on(e,t){let n=this._listeners.get(e);return n||(n=new Set,this._listeners.set(e,n)),n.add(t),this._unprocessedMessages.forEach((e=>{t(...e)&&this._unprocessedMessages.delete(e)})),this}removeAllListeners(e){return e?this._listeners.delete(e):this._listeners.clear(),this}removeListener(e,t){const n=this._listeners.get(e);return n&&n.delete(t),this}sendEvent(){let e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{};this._backend&&this._backend.send({type:"event",data:e})}sendRequest(e){if(!this._backend)return Promise.reject(new Error("No transport backend defined!"));this._requestID++;const t=this._requestID;return new Promise(((n,r)=>{this._responseHandlers.set(t,(e=>{let{error:t,result:i}=e;void 0!==i?n(i):r(void 0!==t?t:new Error("Unexpected response format!"))}));try{this._backend.send({type:_,data:e,id:t})}catch(e){this._responseHandlers.delete(t),r(e)}}))}setBackend(e){this._disposeBackend(),this._backend=e,this._backend.setReceiveCallback(this._onMessageReceived.bind(this))}}let L;try{L=function(e,t=!1,n="hash"){if(!e)return{};"string"==typeof e&&(e=new URL(e));const r="search"===n?e.search:e.hash,i={},s=r?.substr(1).split("&")||[];if("hash"===n&&1===s.length){const e=s[0];if(e.startsWith("/")&&1===e.split("&").length)return i}return s.forEach((e=>{const n=e.split("="),r=n[0];if(!r||r.split(".").some((e=>d.includes(e))))return;let s;try{if(s=n[1],!t){const e=decodeURIComponent(s).replace(/\\&/,"&");s="undefined"===e?void 0:c(e)}}catch(e){return void function(e,t=""){console.error(t,e),window.onerror?.(t,void 0,void 0,void 0,e)}(e,`Failed to parse URL parameter value: ${String(s)}`)}i[r]=s})),i}(window.location).jitsi_meet_external_api_id}catch(e){}(window.JitsiMeetJS||(window.JitsiMeetJS={}),window.JitsiMeetJS.app||(window.JitsiMeetJS.app={}),window.JitsiMeetJS.app).setExternalTransportBackend=e=>undefined.setBackend(e);var k=n(860);const C=n.n(k)().getLogger("modules/API/external/functions.js");function E(e,t){return e.sendRequest({type:"devices",name:"setDevice",device:t})}const S=["css/all.css","libs/alwaysontop.min.js"],x={addBreakoutRoom:"add-breakout-room",answerKnockingParticipant:"answer-knocking-participant",approveVideo:"approve-video",askToUnmute:"ask-to-unmute",autoAssignToBreakoutRooms:"auto-assign-to-breakout-rooms",avatarUrl:"avatar-url",cancelPrivateChat:"cancel-private-chat",closeBreakoutRoom:"close-breakout-room",displayName:"display-name",endConference:"end-conference",email:"email",grantModerator:"grant-moderator",hangup:"video-hangup",hideNotification:"hide-notification",initiatePrivateChat:"initiate-private-chat",joinBreakoutRoom:"join-breakout-room",localSubject:"local-subject",kickParticipant:"kick-participant",muteEveryone:"mute-everyone",overwriteConfig:"overwrite-config",overwriteNames:"overwrite-names",password:"password",pinParticipant:"pin-participant",rejectParticipant:"reject-participant",removeBreakoutRoom:"remove-breakout-room",resizeFilmStrip:"resize-film-strip",resizeLargeVideo:"resize-large-video",sendCameraFacingMode:"send-camera-facing-mode-message",sendChatMessage:"send-chat-message",sendEndpointTextMessage:"send-endpoint-text-message",sendParticipantToRoom:"send-participant-to-room",sendTones:"send-tones",setAssumedBandwidthBps:"set-assumed-bandwidth-bps",setFollowMe:"set-follow-me",setLargeVideoParticipant:"set-large-video-participant",setMediaEncryptionKey:"set-media-encryption-key",setNoiseSuppressionEnabled:"set-noise-suppression-enabled",setParticipantVolume:"set-participant-volume",setSubtitles:"set-subtitles",setTileView:"set-tile-view",setVideoQuality:"set-video-quality",showNotification:"show-notification",startRecording:"start-recording",startShareVideo:"start-share-video",stopRecording:"stop-recording",stopShareVideo:"stop-share-video",subject:"subject",submitFeedback:"submit-feedback",toggleAudio:"toggle-audio",toggleCamera:"toggle-camera",toggleCameraMirror:"toggle-camera-mirror",toggleChat:"toggle-chat",toggleE2EE:"toggle-e2ee",toggleFilmStrip:"toggle-film-strip",toggleLobby:"toggle-lobby",toggleModeration:"toggle-moderation",toggleNoiseSuppression:"toggle-noise-suppression",toggleParticipantsPane:"toggle-participants-pane",toggleRaiseHand:"toggle-raise-hand",toggleShareScreen:"toggle-share-screen",toggleSubtitles:"toggle-subtitles",toggleTileView:"toggle-tile-view",toggleVirtualBackgroundDialog:"toggle-virtual-background",toggleVideo:"toggle-video",toggleWhiteboard:"toggle-whiteboard"},O={"avatar-changed":"avatarChanged","audio-availability-changed":"audioAvailabilityChanged","audio-mute-status-changed":"audioMuteStatusChanged","audio-or-video-sharing-toggled":"audioOrVideoSharingToggled","breakout-rooms-updated":"breakoutRoomsUpdated","browser-support":"browserSupport","camera-error":"cameraError","chat-updated":"chatUpdated","compute-pressure-changed":"computePressureChanged","content-sharing-participants-changed":"contentSharingParticipantsChanged","data-channel-closed":"dataChannelClosed","data-channel-opened":"dataChannelOpened","device-list-changed":"deviceListChanged","display-name-change":"displayNameChange","dominant-speaker-changed":"dominantSpeakerChanged","email-change":"emailChange","error-occurred":"errorOccurred","endpoint-text-message-received":"endpointTextMessageReceived","face-landmark-detected":"faceLandmarkDetected","feedback-submitted":"feedbackSubmitted","feedback-prompt-displayed":"feedbackPromptDisplayed","filmstrip-display-changed":"filmstripDisplayChanged","incoming-message":"incomingMessage","knocking-participant":"knockingParticipant",log:"log","mic-error":"micError","moderation-participant-approved":"moderationParticipantApproved","moderation-participant-rejected":"moderationParticipantRejected","moderation-status-changed":"moderationStatusChanged","mouse-enter":"mouseEnter","mouse-leave":"mouseLeave","mouse-move":"mouseMove","non-participant-message-received":"nonParticipantMessageReceived","notification-triggered":"notificationTriggered","outgoing-message":"outgoingMessage","p2p-status-changed":"p2pStatusChanged","participant-joined":"participantJoined","participant-kicked-out":"participantKickedOut","participant-left":"participantLeft","participant-role-changed":"participantRoleChanged","participants-pane-toggled":"participantsPaneToggled","password-required":"passwordRequired","peer-connection-failure":"peerConnectionFailure","prejoin-screen-loaded":"prejoinScreenLoaded","proxy-connection-event":"proxyConnectionEvent","raise-hand-updated":"raiseHandUpdated",ready:"ready","recording-link-available":"recordingLinkAvailable","recording-status-changed":"recordingStatusChanged","participant-menu-button-clicked":"participantMenuButtonClick","video-ready-to-close":"readyToClose","video-conference-joined":"videoConferenceJoined","video-conference-left":"videoConferenceLeft","video-availability-changed":"videoAvailabilityChanged","video-mute-status-changed":"videoMuteStatusChanged","video-quality-changed":"videoQualityChanged","screen-sharing-status-changed":"screenSharingStatusChanged","subject-change":"subjectChange","suspend-detected":"suspendDetected","tile-view-changed":"tileViewChanged","toolbar-button-clicked":"toolbarButtonClicked","transcription-chunk-received":"transcriptionChunkReceived","whiteboard-status-changed":"whiteboardStatusChanged"},R={"_request-desktop-sources":"_requestDesktopSources"};let j=0;function I(e,t){e._numberOfParticipants+=t}function P(e){let t;return"string"==typeof e&&null!==String(e).match(/([0-9]*\.?[0-9]+)(em|pt|px|((d|l|s)?v)(h|w)|%)$/)?t=e:"number"==typeof e&&(t=`${e}px`),t}class N extends(i()){constructor(e){super();for(var t=arguments.length,n=new Array(t>1?t-1:0),r=1;r1&&void 0!==arguments[1]?arguments[1]:{},url:`https://${e}/#jitsi_meet_external_api_id=${j}`})}(e,{configOverwrite:d,iceServers:f,interfaceConfigOverwrite:l,jwt:u,lang:p,roomName:i,devices:v,userInfo:_,appData:{localStorageContent:C},release:L}),this._createIFrame(a,s,k),this._transport=new w({backend:new y({postisOptions:{allowedOrigin:new URL(this._url).origin,scope:`jitsi_meet_external_api_${j}`,window:this._frame.contentWindow}})}),Array.isArray(g)&&g.length>0&&this.invite(g),this._onload=h,this._tmpE2EEKey=b,this._isLargeVideoVisible=!1,this._isPrejoinVideoVisible=!1,this._numberOfParticipants=0,this._participants={},this._myUserID=void 0,this._onStageParticipant=void 0,this._setupListeners(),j++}_createIFrame(e,t,n){const r=`jitsiConferenceFrame${j}`;this._frame=document.createElement("iframe"),this._frame.allow=["autoplay","camera","clipboard-write","compute-pressure","display-capture","hid","microphone","screen-wake-lock"].join("; "),this._frame.name=r,this._frame.id=r,this._setSize(e,t),this._frame.setAttribute("allowFullScreen","true"),this._frame.style.border=0,n&&(this._frame.sandbox=n),this._frame.src=this._url,this._frame=this._parentNode.appendChild(this._frame)}_getAlwaysOnTopResources(){const e=this._frame.contentWindow,t=e.document;let n="";const r=t.querySelector("base");if(r&&r.href)n=r.href;else{const{protocol:t,host:r}=e.location;n=`${t}//${r}`}return S.map((e=>new URL(e,n).href))}_getFormattedDisplayName(e){const{formattedDisplayName:t}=this._participants[e]||{};return t}_getOnStageParticipant(){return this._onStageParticipant}_getLargeVideo(){const e=this.getIFrame();if(this._isLargeVideoVisible&&e&&e.contentWindow&&e.contentWindow.document)return e.contentWindow.document.getElementById("largeVideo")}_getPrejoinVideo(){const e=this.getIFrame();if(this._isPrejoinVideoVisible&&e&&e.contentWindow&&e.contentWindow.document)return e.contentWindow.document.getElementById("prejoinVideo")}_getParticipantVideo(e){const t=this.getIFrame();if(t&&t.contentWindow&&t.contentWindow.document)return void 0===e||e===this._myUserID?t.contentWindow.document.getElementById("localVideo_container"):t.contentWindow.document.querySelector(`#participant_${e} video`)}_setSize(e,t){const n=P(e),r=P(t);void 0!==n&&(this._height=e,this._frame.style.height=n),void 0!==r&&(this._width=t,this._frame.style.width=r)}_setupListeners(){this._transport.on("event",(e=>{let{name:t,...n}=e;const r=n.id;switch(t){case"ready":var i;null===(i=this._onload)||void 0===i||i.call(this);break;case"video-conference-joined":if(void 0!==this._tmpE2EEKey){const e=e=>{const t=[];for(let n=0;n{const n=R[e.name],r={...e,name:n};n&&this.emit(n,r,t)}))}updateNumberOfParticipants(e){if(!e||!Object.keys(e).length)return;const t=Object.keys(e).reduce(((t,n)=>{var r;return null!==(r=e[n])&&void 0!==r&&r.participants?Object.keys(e[n].participants).length+t:t}),0);this._numberOfParticipants=t}async getRoomsInfo(){return this._transport.sendRequest({name:"rooms-info"})}isP2pActive(){return this._transport.sendRequest({name:"get-p2p-status"})}addEventListener(e,t){this.on(e,t)}addEventListeners(e){for(const t in e)this.addEventListener(t,e[t])}captureLargeVideoScreenshot(){return this._transport.sendRequest({name:"capture-largevideo-screenshot"})}dispose(){this.emit("_willDispose"),this._transport.dispose(),this.removeAllListeners(),this._frame&&this._frame.parentNode&&this._frame.parentNode.removeChild(this._frame)}executeCommand(e){if(e in x){for(var t=arguments.length,n=new Array(t>1?t-1:0),r=1;r(C.error(e),{})))}(this._transport)}getContentSharingParticipants(){return this._transport.sendRequest({name:"get-content-sharing-participants"})}getCurrentDevices(){return function(e){return e.sendRequest({type:"devices",name:"getCurrentDevices"}).catch((e=>(C.error(e),{})))}(this._transport)}getCustomAvatarBackgrounds(){return this._transport.sendRequest({name:"get-custom-avatar-backgrounds"})}getLivestreamUrl(){return this._transport.sendRequest({name:"get-livestream-url"})}getParticipantsInfo(){const e=Object.keys(this._participants),t=Object.values(this._participants);return t.forEach(((t,n)=>{t.participantId=e[n]})),t}getVideoQuality(){return this._videoQuality}isAudioAvailable(){return this._transport.sendRequest({name:"is-audio-available"})}isDeviceChangeAvailable(e){return function(e,t){return e.sendRequest({deviceType:t,type:"devices",name:"isDeviceChangeAvailable"})}(this._transport,e)}isDeviceListAvailable(){return function(e){return e.sendRequest({type:"devices",name:"isDeviceListAvailable"})}(this._transport)}isMultipleAudioInputSupported(){return function(e){return e.sendRequest({type:"devices",name:"isMultipleAudioInputSupported"})}(this._transport)}invite(e){return Array.isArray(e)&&0!==e.length?this._transport.sendRequest({name:"invite",invitees:e}):Promise.reject(new TypeError("Invalid Argument"))}isAudioMuted(){return this._transport.sendRequest({name:"is-audio-muted"})}isAudioDisabled(){return this._transport.sendRequest({name:"is-audio-disabled"})}isModerationOn(e){return this._transport.sendRequest({name:"is-moderation-on",mediaType:e})}isParticipantForceMuted(e,t){return this._transport.sendRequest({name:"is-participant-force-muted",participantId:e,mediaType:t})}isParticipantsPaneOpen(){return this._transport.sendRequest({name:"is-participants-pane-open"})}isSharingScreen(){return this._transport.sendRequest({name:"is-sharing-screen"})}isStartSilent(){return this._transport.sendRequest({name:"is-start-silent"})}getAvatarURL(e){const{avatarURL:t}=this._participants[e]||{};return t}getDeploymentInfo(){return this._transport.sendRequest({name:"deployment-info"})}getDisplayName(e){const{displayName:t}=this._participants[e]||{};return t}getEmail(e){const{email:t}=this._participants[e]||{};return t}getIFrame(){return this._frame}getNumberOfParticipants(){return this._numberOfParticipants}getSupportedCommands(){return Object.keys(x)}getSupportedEvents(){return Object.values(O)}isVideoAvailable(){return this._transport.sendRequest({name:"is-video-available"})}isVideoMuted(){return this._transport.sendRequest({name:"is-video-muted"})}listBreakoutRooms(){return this._transport.sendRequest({name:"list-breakout-rooms"})}_isNewElectronScreensharingSupported(){return this._transport.sendRequest({name:"_new_electron_screensharing_supported"})}pinParticipant(e,t){this.executeCommand("pinParticipant",e,t)}removeEventListener(e){this.removeAllListeners(e)}removeEventListeners(e){e.forEach((e=>this.removeEventListener(e)))}resizeLargeVideo(e,t){e<=this._width&&t<=this._height&&this.executeCommand("resizeLargeVideo",e,t)}sendProxyConnectionEvent(e){this._transport.sendEvent({data:[e],name:"proxy-connection-event"})}setAudioInputDevice(e,t){return function(e,t,n){return E(e,{id:n,kind:"audioinput",label:t})}(this._transport,e,t)}setAudioOutputDevice(e,t){return function(e,t,n){return E(e,{id:n,kind:"audiooutput",label:t})}(this._transport,e,t)}setLargeVideoParticipant(e,t){this.executeCommand("setLargeVideoParticipant",e,t)}setVideoInputDevice(e,t){return function(e,t,n){return E(e,{id:n,kind:"videoinput",label:t})}(this._transport,e,t)}startRecording(e){this.executeCommand("startRecording",e)}stopRecording(e){this.executeCommand("stopRecording",e)}toggleE2EE(e){this.executeCommand("toggleE2EE",e)}async setMediaEncryptionKey(e){const{key:t,index:n}=e;if(t){const e=await crypto.subtle.exportKey("raw",t);this.executeCommand("setMediaEncryptionKey",JSON.stringify({exportedKey:Array.from(new Uint8Array(e)),index:n}))}else this.executeCommand("setMediaEncryptionKey",JSON.stringify({exportedKey:!1,index:n}))}}},872:(e,t,n)=>{e.exports=n(372).default},571:(e,t)=>{"use strict";const n=/"(?:_|\\u005[Ff])(?:_|\\u005[Ff])(?:p|\\u0070)(?:r|\\u0072)(?:o|\\u006[Ff])(?:t|\\u0074)(?:o|\\u006[Ff])(?:_|\\u005[Ff])(?:_|\\u005[Ff])"\s*\:/;t.parse=function(e){const r="object"==typeof(arguments.length<=1?void 0:arguments[1])&&(arguments.length<=1?void 0:arguments[1]),i=(arguments.length<=1?0:arguments.length-1)>1||!r?arguments.length<=1?void 0:arguments[1]:void 0,s=(arguments.length<=1?0:arguments.length-1)>1&&(arguments.length<=2?void 0:arguments[2])||r||{},o=JSON.parse(e,i);return"ignore"===s.protoAction?o:o&&"object"==typeof o&&e.match(n)?(t.scan(o,s),o):o},t.scan=function(e){let t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{},n=[e];for(;n.length;){const e=n;n=[];for(const r of e){if(Object.prototype.hasOwnProperty.call(r,"__proto__")){if("remove"!==t.protoAction)throw new SyntaxError("Object contains forbidden prototype property");delete r.__proto__}for(const e in r){const t=r[e];t&&"object"==typeof t&&n.push(r[e])}}}},t.safeParse=function(e,n){try{return t.parse(e,n)}catch(e){return null}}},369:(e,t,n)=>{var r=n(7);function i(e,t){this.logStorage=e,this.stringifyObjects=!(!t||!t.stringifyObjects)&&t.stringifyObjects,this.storeInterval=t&&t.storeInterval?t.storeInterval:3e4,this.maxEntryLength=t&&t.maxEntryLength?t.maxEntryLength:1e4,Object.values(r.levels).forEach(function(e){this[e]=function(){this._log.apply(this,arguments)}.bind(this,e)}.bind(this)),this.storeLogsIntervalID=null,this.queue=[],this.totalLen=0,this.outputCache=[]}i.prototype.stringify=function(e){try{return JSON.stringify(e)}catch(e){return"[object with circular refs?]"}},i.prototype.formatLogMessage=function(e){for(var t="",n=1,r=arguments.length;n=this.maxEntryLength&&this._flush(!0,!0)},i.prototype.start=function(){this._reschedulePublishInterval()},i.prototype._reschedulePublishInterval=function(){this.storeLogsIntervalID&&(window.clearTimeout(this.storeLogsIntervalID),this.storeLogsIntervalID=null),this.storeLogsIntervalID=window.setTimeout(this._flush.bind(this,!1,!0),this.storeInterval)},i.prototype.flush=function(){this._flush(!1,!0)},i.prototype._storeLogs=function(e){try{this.logStorage.storeLogs(e)}catch(e){console.error("LogCollector error when calling logStorage.storeLogs(): ",e)}},i.prototype._flush=function(e,t){var n=!1;try{n=this.logStorage.isReady()}catch(e){console.error("LogCollector error when calling logStorage.isReady(): ",e)}this.totalLen>0&&(n||e)&&(n?(this.outputCache.length&&(this.outputCache.forEach(function(e){this._storeLogs(e)}.bind(this)),this.outputCache=[]),this._storeLogs(this.queue)):this.outputCache.push(this.queue),this.queue=[],this.totalLen=0),t&&this._reschedulePublishInterval()},i.prototype.stop=function(){this._flush(!1,!1)},e.exports=i},7:e=>{var t={trace:0,debug:1,info:2,log:3,warn:4,error:5};o.consoleTransport=console;var n=[o.consoleTransport];o.addGlobalTransport=function(e){-1===n.indexOf(e)&&n.push(e)},o.removeGlobalTransport=function(e){var t=n.indexOf(e);-1!==t&&n.splice(t,1)};var r={};function i(){var e={methodName:"",fileLocation:"",line:null,column:null},t=new Error,n=t.stack?t.stack.split("\n"):[];if(!n||n.length<3)return e;var r=null;return n[3]&&(r=n[3].match(/\s*at\s*(.+?)\s*\((\S*)\s*:(\d*)\s*:(\d*)\)/)),!r||r.length<=4?(0===n[2].indexOf("log@")?e.methodName=n[3].substr(0,n[3].indexOf("@")):e.methodName=n[2].substr(0,n[2].indexOf("@")),e):(e.methodName=r[1],e.fileLocation=r[2],e.line=r[3],e.column=r[4],e)}function s(){var e=arguments[0],s=arguments[1],o=Array.prototype.slice.call(arguments,2);if(!(t[s]1&&p.push("<"+a.methodName+">: ");var h=p.concat(o);try{u.bind(l).apply(l,h)}catch(e){console.error("An error occured when trying to log with one of the available transports",e)}}}}function o(e,n,r,i){this.id=n,this.options=i||{},this.transports=r,this.transports||(this.transports=[]),this.level=t[e];for(var o=Object.keys(t),a=0;a{var r=n(7),i=n(369),s={},o=[],a=r.levels.TRACE;e.exports={addGlobalTransport:function(e){r.addGlobalTransport(e)},removeGlobalTransport:function(e){r.removeGlobalTransport(e)},setGlobalOptions:function(e){r.setGlobalOptions(e)},getLogger:function(e,t,n){var i=new r(a,e,t,n);return e?(s[e]=s[e]||[],s[e].push(i)):o.push(i),i},getUntrackedLogger:function(e,t,n){return new r(a,e,t,n)},setLogLevelById:function(e,t){for(var n=t?s[t]||[]:o,r=0;r{"use strict";var t,n="object"==typeof Reflect?Reflect:null,r=n&&"function"==typeof n.apply?n.apply:function(e,t,n){return Function.prototype.apply.call(e,t,n)};t=n&&"function"==typeof n.ownKeys?n.ownKeys:Object.getOwnPropertySymbols?function(e){return Object.getOwnPropertyNames(e).concat(Object.getOwnPropertySymbols(e))}:function(e){return Object.getOwnPropertyNames(e)};var i=Number.isNaN||function(e){return e!=e};function s(){s.init.call(this)}e.exports=s,e.exports.once=function(e,t){return new Promise((function(n,r){function i(n){e.removeListener(t,s),r(n)}function s(){"function"==typeof e.removeListener&&e.removeListener("error",i),n([].slice.call(arguments))}m(e,t,s,{once:!0}),"error"!==t&&function(e,t,n){"function"==typeof e.on&&m(e,"error",t,{once:!0})}(e,i)}))},s.EventEmitter=s,s.prototype._events=void 0,s.prototype._eventsCount=0,s.prototype._maxListeners=void 0;var o=10;function a(e){if("function"!=typeof e)throw new TypeError('The "listener" argument must be of type Function. Received type '+typeof e)}function c(e){return void 0===e._maxListeners?s.defaultMaxListeners:e._maxListeners}function d(e,t,n,r){var i,s,o,d;if(a(n),void 0===(s=e._events)?(s=e._events=Object.create(null),e._eventsCount=0):(void 0!==s.newListener&&(e.emit("newListener",t,n.listener?n.listener:n),s=e._events),o=s[t]),void 0===o)o=s[t]=n,++e._eventsCount;else if("function"==typeof o?o=s[t]=r?[n,o]:[o,n]:r?o.unshift(n):o.push(n),(i=c(e))>0&&o.length>i&&!o.warned){o.warned=!0;var l=new Error("Possible EventEmitter memory leak detected. "+o.length+" "+String(t)+" listeners added. Use emitter.setMaxListeners() to increase limit");l.name="MaxListenersExceededWarning",l.emitter=e,l.type=t,l.count=o.length,d=l,console&&console.warn&&console.warn(d)}return e}function l(){if(!this.fired)return this.target.removeListener(this.type,this.wrapFn),this.fired=!0,0===arguments.length?this.listener.call(this.target):this.listener.apply(this.target,arguments)}function u(e,t,n){var r={fired:!1,wrapFn:void 0,target:e,type:t,listener:n},i=l.bind(r);return i.listener=n,r.wrapFn=i,i}function p(e,t,n){var r=e._events;if(void 0===r)return[];var i=r[t];return void 0===i?[]:"function"==typeof i?n?[i.listener||i]:[i]:n?function(e){for(var t=new Array(e.length),n=0;n0&&(o=t[0]),o instanceof Error)throw o;var a=new Error("Unhandled error."+(o?" ("+o.message+")":""));throw a.context=o,a}var c=s[e];if(void 0===c)return!1;if("function"==typeof c)r(c,this,t);else{var d=c.length,l=g(c,d);for(n=0;n=0;s--)if(n[s]===t||n[s].listener===t){o=n[s].listener,i=s;break}if(i<0)return this;0===i?n.shift():function(e,t){for(;t+1=0;r--)this.removeListener(e,t[r]);return this},s.prototype.listeners=function(e){return p(this,e,!0)},s.prototype.rawListeners=function(e){return p(this,e,!1)},s.listenerCount=function(e,t){return"function"==typeof e.listenerCount?e.listenerCount(t):h.call(e,t)},s.prototype.listenerCount=h,s.prototype.eventNames=function(){return this._eventsCount>0?t(this._events):[]}}},t={};function n(r){var i=t[r];if(void 0!==i)return i.exports;var s=t[r]={exports:{}};return e[r](s,s.exports,n),s.exports}return n.n=e=>{var t=e&&e.__esModule?()=>e.default:()=>e;return n.d(t,{a:t}),t},n.d=(e,t)=>{for(var r in t)n.o(t,r)&&!n.o(e,r)&&Object.defineProperty(e,r,{enumerable:!0,get:t[r]})},n.o=(e,t)=>Object.prototype.hasOwnProperty.call(e,t),n(872)})())); +!function(e,t){"object"==typeof exports&&"object"==typeof module?module.exports=t():"function"==typeof define&&define.amd?define([],t):"object"==typeof exports?exports.JitsiMeetExternalAPI=t():e.JitsiMeetExternalAPI=t()}(self,(()=>(()=>{var e={372:(e,t,n)=>{"use strict";n.d(t,{default:()=>D});var r=n(620),i=n.n(r);class s extends r{constructor(){var e,t,n;super(...arguments),e=this,n={},(t=function(e){var t=function(e,t){if("object"!=typeof e||!e)return e;var n=e[Symbol.toPrimitive];if(void 0!==n){var r=n.call(e,"string");if("object"!=typeof r)return r;throw new TypeError("@@toPrimitive must return a primitive value.")}return String(e)}(e);return"symbol"==typeof t?t:t+""}(t="_storage"))in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n}clear(){this._storage={}}get length(){return Object.keys(this._storage).length}getItem(e){return this._storage[e]}setItem(e,t){this._storage[e]=t}removeItem(e){delete this._storage[e]}key(e){const t=Object.keys(this._storage);if(!(t.length<=e))return t[e]}serialize(){let e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:[];if(0===e.length)return JSON.stringify(this._storage);const t={...this._storage};return e.forEach((e=>{delete t[e]})),JSON.stringify(t)}}const o=new class extends r{constructor(){super();try{this._storage=window.localStorage,this._localStorageDisabled=!1}catch(e){}this._storage||(console.warn("Local storage is disabled."),this._storage=new s,this._localStorageDisabled=!0)}isLocalStorageDisabled(){return this._localStorageDisabled}setLocalStorageDisabled(e){this._localStorageDisabled=e;try{this._storage=e?new s:window.localStorage}catch(e){}this._storage||(this._storage=new s)}clear(){this._storage.clear(),this.emit("changed")}get length(){return this._storage.length}getItem(e){return this._storage.getItem(e)}setItem(e,t){let n=arguments.length>2&&void 0!==arguments[2]&&arguments[2];this._storage.setItem(e,t),n||this.emit("changed")}removeItem(e){this._storage.removeItem(e),this.emit("changed")}key(e){return this._storage.key(e)}serialize(){let e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:[];if(this.isLocalStorageDisabled())return this._storage.serialize(e);const t=this._storage.length,n={};for(let r=0;r0&&void 0!==arguments[0]?arguments[0]:{};this.postis=function(e){var t,n=e.scope,r=e.window,i=e.windowForEventListening||window,s=e.allowedOrigin,o={},a=[],l={},d=!1,u="__ready__",h=function(e){var t;try{t=c(e.data)}catch(e){return}if((!s||e.origin===s)&&t&&t.postis&&t.scope===n){var r=o[t.method];if(r)for(var i=0;i{},this.postis.listen(_,(e=>this._receiveCallback(e)))}dispose(){this.postis.destroy()}send(e){this.postis.send({method:_,params:e})}setReceiveCallback(e){this._receiveCallback=e}}const w="request",L="response";class k{constructor(){let{backend:e}=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{};this._listeners=new Map,this._requestID=0,this._responseHandlers=new Map,this._unprocessedMessages=new Set,this.addListener=this.on,e&&this.setBackend(e)}_disposeBackend(){this._backend&&(this._backend.dispose(),this._backend=null)}_onMessageReceived(e){if(e.type===L){const t=this._responseHandlers.get(e.id);t&&(t(e),this._responseHandlers.delete(e.id))}else e.type===w?this.emit("request",e.data,((t,n)=>{this._backend.send({type:L,error:n,id:e.id,result:t})})):this.emit("event",e.data)}dispose(){this._responseHandlers.clear(),this._unprocessedMessages.clear(),this.removeAllListeners(),this._disposeBackend()}emit(e){for(var t=arguments.length,n=new Array(t>1?t-1:0),r=1;r{s=e(...n)||s})),s||this._unprocessedMessages.add(n),s}on(e,t){let n=this._listeners.get(e);return n||(n=new Set,this._listeners.set(e,n)),n.add(t),this._unprocessedMessages.forEach((e=>{t(...e)&&this._unprocessedMessages.delete(e)})),this}removeAllListeners(e){return e?this._listeners.delete(e):this._listeners.clear(),this}removeListener(e,t){const n=this._listeners.get(e);return n&&n.delete(t),this}sendEvent(){let e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{};this._backend&&this._backend.send({type:"event",data:e})}sendRequest(e){if(!this._backend)return Promise.reject(new Error("No transport backend defined!"));this._requestID++;const t=this._requestID;return new Promise(((n,r)=>{this._responseHandlers.set(t,(e=>{let{error:t,result:i}=e;void 0!==i?n(i):r(void 0!==t?t:new Error("Unexpected response format!"))}));try{this._backend.send({type:w,data:e,id:t})}catch(e){this._responseHandlers.delete(t),r(e)}}))}setBackend(e){this._disposeBackend(),this._backend=e,this._backend.setReceiveCallback(this._onMessageReceived.bind(this))}}let C;try{C=function(e,t=!1,n="hash"){if(!e)return{};"string"==typeof e&&(e=new URL(e));const r="search"===n?e.search:e.hash,i={},s=r?.substr(1).split("&")||[];if("hash"===n&&1===s.length){const e=s[0];if(e.startsWith("/")&&1===e.split("&").length)return i}return s.forEach((e=>{const n=e.split("="),r=n[0];if(!r||r.split(".").some((e=>l.includes(e))))return;let s;try{if(s=n[1],!t){const e=decodeURIComponent(s).replace(/\\&/,"&").replace(/[\u2018\u2019]/g,"'").replace(/[\u201C\u201D]/g,'"');s="undefined"===e?void 0:c(e)}}catch(e){return void function(e,t=""){console.error(t,e),window.onerror?.(t,void 0,void 0,void 0,e)}(e,`Failed to parse URL parameter value: ${String(s)}`)}i[r]=s})),i}(window.location).jitsi_meet_external_api_id}catch(e){}(window.JitsiMeetJS||(window.JitsiMeetJS={}),window.JitsiMeetJS.app||(window.JitsiMeetJS.app={}),window.JitsiMeetJS.app).setExternalTransportBackend=e=>undefined.setBackend(e);var x=n(860);const E=n.n(x)().getLogger("modules/API/external/functions.js");function S(e,t){return e.sendRequest({type:"devices",name:"setDevice",device:t})}const R=["css/all.css","libs/alwaysontop.min.js"],O={addBreakoutRoom:"add-breakout-room",answerKnockingParticipant:"answer-knocking-participant",approveVideo:"approve-video",askToUnmute:"ask-to-unmute",autoAssignToBreakoutRooms:"auto-assign-to-breakout-rooms",avatarUrl:"avatar-url",cancelPrivateChat:"cancel-private-chat",closeBreakoutRoom:"close-breakout-room",displayName:"display-name",endConference:"end-conference",email:"email",grantModerator:"grant-moderator",hangup:"video-hangup",hideNotification:"hide-notification",initiatePrivateChat:"initiate-private-chat",joinBreakoutRoom:"join-breakout-room",localSubject:"local-subject",kickParticipant:"kick-participant",muteEveryone:"mute-everyone",overwriteConfig:"overwrite-config",overwriteNames:"overwrite-names",password:"password",pinParticipant:"pin-participant",rejectParticipant:"reject-participant",removeBreakoutRoom:"remove-breakout-room",resizeFilmStrip:"resize-film-strip",resizeLargeVideo:"resize-large-video",sendCameraFacingMode:"send-camera-facing-mode-message",sendChatMessage:"send-chat-message",sendEndpointTextMessage:"send-endpoint-text-message",sendParticipantToRoom:"send-participant-to-room",sendTones:"send-tones",setAssumedBandwidthBps:"set-assumed-bandwidth-bps",setFollowMe:"set-follow-me",setLargeVideoParticipant:"set-large-video-participant",setMediaEncryptionKey:"set-media-encryption-key",setNoiseSuppressionEnabled:"set-noise-suppression-enabled",setParticipantVolume:"set-participant-volume",setSubtitles:"set-subtitles",setTileView:"set-tile-view",setVideoQuality:"set-video-quality",showNotification:"show-notification",startRecording:"start-recording",startShareVideo:"start-share-video",stopRecording:"stop-recording",stopShareVideo:"stop-share-video",subject:"subject",submitFeedback:"submit-feedback",toggleAudio:"toggle-audio",toggleCamera:"toggle-camera",toggleCameraMirror:"toggle-camera-mirror",toggleChat:"toggle-chat",toggleE2EE:"toggle-e2ee",toggleFilmStrip:"toggle-film-strip",toggleLobby:"toggle-lobby",toggleModeration:"toggle-moderation",toggleNoiseSuppression:"toggle-noise-suppression",toggleParticipantsPane:"toggle-participants-pane",toggleRaiseHand:"toggle-raise-hand",toggleShareScreen:"toggle-share-screen",toggleSubtitles:"toggle-subtitles",toggleTileView:"toggle-tile-view",toggleVirtualBackgroundDialog:"toggle-virtual-background",toggleVideo:"toggle-video",toggleWhiteboard:"toggle-whiteboard"},j={"avatar-changed":"avatarChanged","audio-availability-changed":"audioAvailabilityChanged","audio-mute-status-changed":"audioMuteStatusChanged","audio-or-video-sharing-toggled":"audioOrVideoSharingToggled","breakout-rooms-updated":"breakoutRoomsUpdated","browser-support":"browserSupport","camera-error":"cameraError","chat-updated":"chatUpdated","compute-pressure-changed":"computePressureChanged","conference-created-timestamp":"conferenceCreatedTimestamp","content-sharing-participants-changed":"contentSharingParticipantsChanged","data-channel-closed":"dataChannelClosed","data-channel-opened":"dataChannelOpened","device-list-changed":"deviceListChanged","display-name-change":"displayNameChange","dominant-speaker-changed":"dominantSpeakerChanged","email-change":"emailChange","error-occurred":"errorOccurred","endpoint-text-message-received":"endpointTextMessageReceived","face-landmark-detected":"faceLandmarkDetected","feedback-submitted":"feedbackSubmitted","feedback-prompt-displayed":"feedbackPromptDisplayed","filmstrip-display-changed":"filmstripDisplayChanged","incoming-message":"incomingMessage","knocking-participant":"knockingParticipant",log:"log","mic-error":"micError","moderation-participant-approved":"moderationParticipantApproved","moderation-participant-rejected":"moderationParticipantRejected","moderation-status-changed":"moderationStatusChanged","mouse-enter":"mouseEnter","mouse-leave":"mouseLeave","mouse-move":"mouseMove","non-participant-message-received":"nonParticipantMessageReceived","notification-triggered":"notificationTriggered","outgoing-message":"outgoingMessage","p2p-status-changed":"p2pStatusChanged","participant-joined":"participantJoined","participant-kicked-out":"participantKickedOut","participant-left":"participantLeft","participant-role-changed":"participantRoleChanged","participants-pane-toggled":"participantsPaneToggled","password-required":"passwordRequired","peer-connection-failure":"peerConnectionFailure","prejoin-screen-loaded":"prejoinScreenLoaded","proxy-connection-event":"proxyConnectionEvent","raise-hand-updated":"raiseHandUpdated",ready:"ready","recording-link-available":"recordingLinkAvailable","recording-status-changed":"recordingStatusChanged","participant-menu-button-clicked":"participantMenuButtonClick","video-ready-to-close":"readyToClose","video-conference-joined":"videoConferenceJoined","video-conference-left":"videoConferenceLeft","video-availability-changed":"videoAvailabilityChanged","video-mute-status-changed":"videoMuteStatusChanged","video-quality-changed":"videoQualityChanged","screen-sharing-status-changed":"screenSharingStatusChanged","subject-change":"subjectChange","suspend-detected":"suspendDetected","tile-view-changed":"tileViewChanged","toolbar-button-clicked":"toolbarButtonClicked","transcribing-status-changed":"transcribingStatusChanged","transcription-chunk-received":"transcriptionChunkReceived","whiteboard-status-changed":"whiteboardStatusChanged"},I={"_request-desktop-sources":"_requestDesktopSources"};let P=0;function N(e,t){e._numberOfParticipants+=t}function A(e){let t;return"string"==typeof e&&null!==String(e).match(/([0-9]*\.?[0-9]+)(em|pt|px|((d|l|s)?v)(h|w)|%)$/)?t=e:"number"==typeof e&&(t=`${e}px`),t}class D extends(i()){constructor(e){super();for(var t=arguments.length,n=new Array(t>1?t-1:0),r=1;r1&&void 0!==arguments[1]?arguments[1]:{},url:`https://${e}/#jitsi_meet_external_api_id=${P}`})}(e,{configOverwrite:l,iceServers:y,interfaceConfigOverwrite:d,jwt:u,lang:h,roomName:i,devices:_,userInfo:w,appData:{localStorageContent:E},release:C}),this._createIFrame(a,s,x),this._transport=new k({backend:new b({postisOptions:{allowedOrigin:new URL(this._url).origin,scope:`jitsi_meet_external_api_${P}`,window:this._frame.contentWindow}})}),Array.isArray(v)&&v.length>0&&this.invite(v),this._onload=p,this._tmpE2EEKey=L,this._isLargeVideoVisible=!1,this._isPrejoinVideoVisible=!1,this._numberOfParticipants=0,this._participants={},this._myUserID=void 0,this._onStageParticipant=void 0,this._setupListeners(),P++}_createIFrame(e,t,n){const r=`jitsiConferenceFrame${P}`;this._frame=document.createElement("iframe"),this._frame.allow=["autoplay","camera","clipboard-write","compute-pressure","display-capture","hid","microphone","screen-wake-lock","speaker-selection"].join("; "),this._frame.name=r,this._frame.id=r,this._setSize(e,t),this._frame.setAttribute("allowFullScreen","true"),this._frame.style.border=0,n&&(this._frame.sandbox=n),this._frame.src=this._url,this._frame=this._parentNode.appendChild(this._frame)}_getAlwaysOnTopResources(){const e=this._frame.contentWindow,t=e.document;let n="";const r=t.querySelector("base");if(r&&r.href)n=r.href;else{const{protocol:t,host:r}=e.location;n=`${t}//${r}`}return R.map((e=>new URL(e,n).href))}_getFormattedDisplayName(e){const{formattedDisplayName:t}=this._participants[e]||{};return t}_getOnStageParticipant(){return this._onStageParticipant}_getLargeVideo(){const e=this.getIFrame();if(this._isLargeVideoVisible&&e&&e.contentWindow&&e.contentWindow.document)return e.contentWindow.document.getElementById("largeVideo")}_getPrejoinVideo(){const e=this.getIFrame();if(this._isPrejoinVideoVisible&&e&&e.contentWindow&&e.contentWindow.document)return e.contentWindow.document.getElementById("prejoinVideo")}_getParticipantVideo(e){const t=this.getIFrame();if(t&&t.contentWindow&&t.contentWindow.document)return void 0===e||e===this._myUserID?t.contentWindow.document.getElementById("localVideo_container"):t.contentWindow.document.querySelector(`#participant_${e} video`)}_setSize(e,t){const n=A(e),r=A(t);void 0!==n&&(this._height=e,this._frame.style.height=n),void 0!==r&&(this._width=t,this._frame.style.width=r)}_setupListeners(){this._transport.on("event",(e=>{let{name:t,...n}=e;const r=n.id;switch(t){case"ready":var i;null===(i=this._onload)||void 0===i||i.call(this);break;case"video-conference-joined":if(void 0!==this._tmpE2EEKey){const e=e=>{const t=[];for(let n=0;n{const n=I[e.name],r={...e,name:n};n&&this.emit(n,r,t)}))}updateNumberOfParticipants(e){if(!e||!Object.keys(e).length)return;const t=Object.keys(e).reduce(((t,n)=>{var r;return null!==(r=e[n])&&void 0!==r&&r.participants?Object.keys(e[n].participants).length+t:t}),0);this._numberOfParticipants=t}async getRoomsInfo(){return this._transport.sendRequest({name:"rooms-info"})}isP2pActive(){return this._transport.sendRequest({name:"get-p2p-status"})}addEventListener(e,t){this.on(e,t)}addEventListeners(e){for(const t in e)this.addEventListener(t,e[t])}captureLargeVideoScreenshot(){return this._transport.sendRequest({name:"capture-largevideo-screenshot"})}dispose(){this.emit("_willDispose"),this._transport.dispose(),this.removeAllListeners(),this._frame&&this._frame.parentNode&&this._frame.parentNode.removeChild(this._frame)}executeCommand(e){if(e in O){for(var t=arguments.length,n=new Array(t>1?t-1:0),r=1;r(E.error(e),{})))}(this._transport)}getContentSharingParticipants(){return this._transport.sendRequest({name:"get-content-sharing-participants"})}getCurrentDevices(){return function(e){return e.sendRequest({type:"devices",name:"getCurrentDevices"}).catch((e=>(E.error(e),{})))}(this._transport)}getCustomAvatarBackgrounds(){return this._transport.sendRequest({name:"get-custom-avatar-backgrounds"})}getLivestreamUrl(){return this._transport.sendRequest({name:"get-livestream-url"})}getParticipantsInfo(){const e=Object.keys(this._participants),t=Object.values(this._participants);return t.forEach(((t,n)=>{t.participantId=e[n]})),t}getVideoQuality(){return this._videoQuality}isAudioAvailable(){return this._transport.sendRequest({name:"is-audio-available"})}isDeviceChangeAvailable(e){return function(e,t){return e.sendRequest({deviceType:t,type:"devices",name:"isDeviceChangeAvailable"})}(this._transport,e)}isDeviceListAvailable(){return function(e){return e.sendRequest({type:"devices",name:"isDeviceListAvailable"})}(this._transport)}isMultipleAudioInputSupported(){return function(e){return e.sendRequest({type:"devices",name:"isMultipleAudioInputSupported"})}(this._transport)}invite(e){return Array.isArray(e)&&0!==e.length?this._transport.sendRequest({name:"invite",invitees:e}):Promise.reject(new TypeError("Invalid Argument"))}isAudioMuted(){return this._transport.sendRequest({name:"is-audio-muted"})}isAudioDisabled(){return this._transport.sendRequest({name:"is-audio-disabled"})}isModerationOn(e){return this._transport.sendRequest({name:"is-moderation-on",mediaType:e})}isParticipantForceMuted(e,t){return this._transport.sendRequest({name:"is-participant-force-muted",participantId:e,mediaType:t})}isParticipantsPaneOpen(){return this._transport.sendRequest({name:"is-participants-pane-open"})}isSharingScreen(){return this._transport.sendRequest({name:"is-sharing-screen"})}isStartSilent(){return this._transport.sendRequest({name:"is-start-silent"})}getAvatarURL(e){const{avatarURL:t}=this._participants[e]||{};return t}getDeploymentInfo(){return this._transport.sendRequest({name:"deployment-info"})}getDisplayName(e){const{displayName:t}=this._participants[e]||{};return t}getEmail(e){const{email:t}=this._participants[e]||{};return t}getIFrame(){return this._frame}getNumberOfParticipants(){return this._numberOfParticipants}getSessionId(){return this._transport.sendRequest({name:"session-id"})}getSupportedCommands(){return Object.keys(O)}getSupportedEvents(){return Object.values(j)}isVideoAvailable(){return this._transport.sendRequest({name:"is-video-available"})}isVideoMuted(){return this._transport.sendRequest({name:"is-video-muted"})}listBreakoutRooms(){return this._transport.sendRequest({name:"list-breakout-rooms"})}_isNewElectronScreensharingSupported(){return this._transport.sendRequest({name:"_new_electron_screensharing_supported"})}pinParticipant(e,t){this.executeCommand("pinParticipant",e,t)}removeEventListener(e){this.removeAllListeners(e)}removeEventListeners(e){e.forEach((e=>this.removeEventListener(e)))}resizeLargeVideo(e,t){e<=this._width&&t<=this._height&&this.executeCommand("resizeLargeVideo",e,t)}sendProxyConnectionEvent(e){this._transport.sendEvent({data:[e],name:"proxy-connection-event"})}setAudioInputDevice(e,t){return function(e,t,n){return S(e,{id:n,kind:"audioinput",label:t})}(this._transport,e,t)}setAudioOutputDevice(e,t){return function(e,t,n){return S(e,{id:n,kind:"audiooutput",label:t})}(this._transport,e,t)}setLargeVideoParticipant(e,t){this.executeCommand("setLargeVideoParticipant",e,t)}setVideoInputDevice(e,t){return function(e,t,n){return S(e,{id:n,kind:"videoinput",label:t})}(this._transport,e,t)}startRecording(e){this.executeCommand("startRecording",e)}stopRecording(e,t){this.executeCommand("stopRecording",e,t)}toggleE2EE(e){this.executeCommand("toggleE2EE",e)}async setMediaEncryptionKey(e){const{key:t,index:n}=e;if(t){const e=await crypto.subtle.exportKey("raw",t);this.executeCommand("setMediaEncryptionKey",JSON.stringify({exportedKey:Array.from(new Uint8Array(e)),index:n}))}else this.executeCommand("setMediaEncryptionKey",JSON.stringify({exportedKey:!1,index:n}))}}},872:(e,t,n)=>{e.exports=n(372).default},135:(e,t)=>{"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.BLANK_URL=t.relativeFirstCharacters=t.urlSchemeRegex=t.ctrlCharactersRegex=t.htmlCtrlEntityRegex=t.htmlEntitiesRegex=t.invalidProtocolRegex=void 0,t.invalidProtocolRegex=/^([^\w]*)(javascript|data|vbscript)/im,t.htmlEntitiesRegex=/&#(\w+)(^\w|;)?/g,t.htmlCtrlEntityRegex=/&(newline|tab);/gi,t.ctrlCharactersRegex=/[\u0000-\u001F\u007F-\u009F\u2000-\u200D\uFEFF]/gim,t.urlSchemeRegex=/^.+(:|:)/gim,t.relativeFirstCharacters=[".","/"],t.BLANK_URL="about:blank"},449:(e,t,n)=>{"use strict";n(135)},571:(e,t)=>{"use strict";const n=/"(?:_|\\u005[Ff])(?:_|\\u005[Ff])(?:p|\\u0070)(?:r|\\u0072)(?:o|\\u006[Ff])(?:t|\\u0074)(?:o|\\u006[Ff])(?:_|\\u005[Ff])(?:_|\\u005[Ff])"\s*\:/;t.parse=function(e){const r="object"==typeof(arguments.length<=1?void 0:arguments[1])&&(arguments.length<=1?void 0:arguments[1]),i=(arguments.length<=1?0:arguments.length-1)>1||!r?arguments.length<=1?void 0:arguments[1]:void 0,s=(arguments.length<=1?0:arguments.length-1)>1&&(arguments.length<=2?void 0:arguments[2])||r||{},o=JSON.parse(e,i);return"ignore"===s.protoAction?o:o&&"object"==typeof o&&e.match(n)?(t.scan(o,s),o):o},t.scan=function(e){let t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{},n=[e];for(;n.length;){const e=n;n=[];for(const r of e){if(Object.prototype.hasOwnProperty.call(r,"__proto__")){if("remove"!==t.protoAction)throw new SyntaxError("Object contains forbidden prototype property");delete r.__proto__}for(const e in r){const t=r[e];t&&"object"==typeof t&&n.push(r[e])}}}},t.safeParse=function(e,n){try{return t.parse(e,n)}catch(e){return null}}},369:(e,t,n)=>{var r=n(7);function i(e,t){this.logStorage=e,this.stringifyObjects=!(!t||!t.stringifyObjects)&&t.stringifyObjects,this.storeInterval=t&&t.storeInterval?t.storeInterval:3e4,this.maxEntryLength=t&&t.maxEntryLength?t.maxEntryLength:1e4,Object.values(r.levels).forEach(function(e){this[e]=function(){this._log.apply(this,arguments)}.bind(this,e)}.bind(this)),this.storeLogsIntervalID=null,this.queue=[],this.totalLen=0,this.outputCache=[]}i.prototype.stringify=function(e){try{return JSON.stringify(e)}catch(e){return"[object with circular refs?]"}},i.prototype.formatLogMessage=function(e){for(var t="",n=1,r=arguments.length;n=this.maxEntryLength&&this._flush(!0,!0)},i.prototype.start=function(){this._reschedulePublishInterval()},i.prototype._reschedulePublishInterval=function(){this.storeLogsIntervalID&&(window.clearTimeout(this.storeLogsIntervalID),this.storeLogsIntervalID=null),this.storeLogsIntervalID=window.setTimeout(this._flush.bind(this,!1,!0),this.storeInterval)},i.prototype.flush=function(){this._flush(!1,!0)},i.prototype._storeLogs=function(e){try{this.logStorage.storeLogs(e)}catch(e){console.error("LogCollector error when calling logStorage.storeLogs(): ",e)}},i.prototype._flush=function(e,t){var n=!1;try{n=this.logStorage.isReady()}catch(e){console.error("LogCollector error when calling logStorage.isReady(): ",e)}this.totalLen>0&&(n||e)&&(n?(this.outputCache.length&&(this.outputCache.forEach(function(e){this._storeLogs(e)}.bind(this)),this.outputCache=[]),this._storeLogs(this.queue)):this.outputCache.push(this.queue),this.queue=[],this.totalLen=0),t&&this._reschedulePublishInterval()},i.prototype.stop=function(){this._flush(!1,!1)},e.exports=i},7:e=>{var t={trace:0,debug:1,info:2,log:3,warn:4,error:5};s.consoleTransport=console;var n=[s.consoleTransport];s.addGlobalTransport=function(e){-1===n.indexOf(e)&&n.push(e)},s.removeGlobalTransport=function(e){var t=n.indexOf(e);-1!==t&&n.splice(t,1)};var r={};function i(){var e=arguments[0],i=arguments[1],s=Array.prototype.slice.call(arguments,2);if(!(t[i]1&&u.push("<"+o.methodName+">: ");var h=u.concat(s);try{d.bind(l).apply(l,h)}catch(e){console.error("An error occured when trying to log with one of the available transports",e)}}}}function s(e,n,r,s){this.id=n,this.options=s||{},this.transports=r,this.transports||(this.transports=[]),this.level=t[e];for(var o=Object.keys(t),a=0;a{var r=n(7),i=n(369),s={},o=[],a=r.levels.TRACE;e.exports={addGlobalTransport:function(e){r.addGlobalTransport(e)},removeGlobalTransport:function(e){r.removeGlobalTransport(e)},setGlobalOptions:function(e){r.setGlobalOptions(e)},getLogger:function(e,t,n){var i=new r(a,e,t,n);return e?(s[e]=s[e]||[],s[e].push(i)):o.push(i),i},getUntrackedLogger:function(e,t,n){return new r(a,e,t,n)},setLogLevelById:function(e,t){for(var n=t?s[t]||[]:o,r=0;r{"use strict";var t,n="object"==typeof Reflect?Reflect:null,r=n&&"function"==typeof n.apply?n.apply:function(e,t,n){return Function.prototype.apply.call(e,t,n)};t=n&&"function"==typeof n.ownKeys?n.ownKeys:Object.getOwnPropertySymbols?function(e){return Object.getOwnPropertyNames(e).concat(Object.getOwnPropertySymbols(e))}:function(e){return Object.getOwnPropertyNames(e)};var i=Number.isNaN||function(e){return e!=e};function s(){s.init.call(this)}e.exports=s,e.exports.once=function(e,t){return new Promise((function(n,r){function i(n){e.removeListener(t,s),r(n)}function s(){"function"==typeof e.removeListener&&e.removeListener("error",i),n([].slice.call(arguments))}m(e,t,s,{once:!0}),"error"!==t&&function(e,t,n){"function"==typeof e.on&&m(e,"error",t,{once:!0})}(e,i)}))},s.EventEmitter=s,s.prototype._events=void 0,s.prototype._eventsCount=0,s.prototype._maxListeners=void 0;var o=10;function a(e){if("function"!=typeof e)throw new TypeError('The "listener" argument must be of type Function. Received type '+typeof e)}function c(e){return void 0===e._maxListeners?s.defaultMaxListeners:e._maxListeners}function l(e,t,n,r){var i,s,o,l;if(a(n),void 0===(s=e._events)?(s=e._events=Object.create(null),e._eventsCount=0):(void 0!==s.newListener&&(e.emit("newListener",t,n.listener?n.listener:n),s=e._events),o=s[t]),void 0===o)o=s[t]=n,++e._eventsCount;else if("function"==typeof o?o=s[t]=r?[n,o]:[o,n]:r?o.unshift(n):o.push(n),(i=c(e))>0&&o.length>i&&!o.warned){o.warned=!0;var d=new Error("Possible EventEmitter memory leak detected. "+o.length+" "+String(t)+" listeners added. Use emitter.setMaxListeners() to increase limit");d.name="MaxListenersExceededWarning",d.emitter=e,d.type=t,d.count=o.length,l=d,console&&console.warn&&console.warn(l)}return e}function d(){if(!this.fired)return this.target.removeListener(this.type,this.wrapFn),this.fired=!0,0===arguments.length?this.listener.call(this.target):this.listener.apply(this.target,arguments)}function u(e,t,n){var r={fired:!1,wrapFn:void 0,target:e,type:t,listener:n},i=d.bind(r);return i.listener=n,r.wrapFn=i,i}function h(e,t,n){var r=e._events;if(void 0===r)return[];var i=r[t];return void 0===i?[]:"function"==typeof i?n?[i.listener||i]:[i]:n?function(e){for(var t=new Array(e.length),n=0;n0&&(o=t[0]),o instanceof Error)throw o;var a=new Error("Unhandled error."+(o?" ("+o.message+")":""));throw a.context=o,a}var c=s[e];if(void 0===c)return!1;if("function"==typeof c)r(c,this,t);else{var l=c.length,d=g(c,l);for(n=0;n=0;s--)if(n[s]===t||n[s].listener===t){o=n[s].listener,i=s;break}if(i<0)return this;0===i?n.shift():function(e,t){for(;t+1=0;r--)this.removeListener(e,t[r]);return this},s.prototype.listeners=function(e){return h(this,e,!0)},s.prototype.rawListeners=function(e){return h(this,e,!1)},s.listenerCount=function(e,t){return"function"==typeof e.listenerCount?e.listenerCount(t):p.call(e,t)},s.prototype.listenerCount=p,s.prototype.eventNames=function(){return this._eventsCount>0?t(this._events):[]}}},t={};function n(r){var i=t[r];if(void 0!==i)return i.exports;var s=t[r]={exports:{}};return e[r](s,s.exports,n),s.exports}return n.n=e=>{var t=e&&e.__esModule?()=>e.default:()=>e;return n.d(t,{a:t}),t},n.d=(e,t)=>{for(var r in t)n.o(t,r)&&!n.o(e,r)&&Object.defineProperty(e,r,{enumerable:!0,get:t[r]})},n.o=(e,t)=>Object.prototype.hasOwnProperty.call(e,t),n(872)})())); //# sourceMappingURL=external_api.min.js.map \ No newline at end of file diff --git a/src/DecryptionFailureTracker.ts b/src/DecryptionFailureTracker.ts index d3f2ad2671..1e07ba252b 100644 --- a/src/DecryptionFailureTracker.ts +++ b/src/DecryptionFailureTracker.ts @@ -82,6 +82,10 @@ export class DecryptionFailureTracker { return "HistoricalMessage"; case DecryptionFailureCode.HISTORICAL_MESSAGE_USER_NOT_JOINED: return "ExpectedDueToMembership"; + case DecryptionFailureCode.SENDER_IDENTITY_PREVIOUSLY_VERIFIED: + return "ExpectedVerificationViolation"; + case DecryptionFailureCode.UNSIGNED_SENDER_DEVICE: + return "ExpectedSentByInsecureDevice"; default: return "UnknownError"; } diff --git a/src/DeviceListener.ts b/src/DeviceListener.ts index ea812d7379..3cf153fc58 100644 --- a/src/DeviceListener.ts +++ b/src/DeviceListener.ts @@ -292,27 +292,21 @@ export default class DeviceListener { await crypto.getUserDeviceInfo([cli.getSafeUserId()]); // cross signing isn't enabled - nag to enable it - // There are 3 different toasts for: + // There are 2 different toasts for: if (!(await crypto.getCrossSigningKeyId()) && (await crypto.userHasCrossSigningKeys())) { // Cross-signing on account but this device doesn't trust the master key (verify this session) showSetupEncryptionToast(SetupKind.VERIFY_THIS_SESSION); this.checkKeyBackupStatus(); } else { - const backupInfo = await this.getKeyBackupInfo(); - if (backupInfo) { - // No cross-signing on account but key backup available (upgrade encryption) - showSetupEncryptionToast(SetupKind.UPGRADE_ENCRYPTION); + // No cross-signing or key backup on account (set up encryption) + await cli.waitForClientWellKnown(); + if (isSecureBackupRequired(cli) && isLoggedIn()) { + // If we're meant to set up, and Secure Backup is required, + // trigger the flow directly without a toast once logged in. + hideSetupEncryptionToast(); + accessSecretStorage(); } else { - // No cross-signing or key backup on account (set up encryption) - await cli.waitForClientWellKnown(); - if (isSecureBackupRequired(cli) && isLoggedIn()) { - // If we're meant to set up, and Secure Backup is required, - // trigger the flow directly without a toast once logged in. - hideSetupEncryptionToast(); - accessSecretStorage(); - } else { - showSetupEncryptionToast(SetupKind.SET_UP_ENCRYPTION); - } + showSetupEncryptionToast(SetupKind.SET_UP_ENCRYPTION); } } } diff --git a/src/async-components/views/dialogs/security/CreateSecretStorageDialog.tsx b/src/async-components/views/dialogs/security/CreateSecretStorageDialog.tsx index 2278fb3806..3022aa6b8d 100644 --- a/src/async-components/views/dialogs/security/CreateSecretStorageDialog.tsx +++ b/src/async-components/views/dialogs/security/CreateSecretStorageDialog.tsx @@ -11,7 +11,7 @@ import React, { createRef } from "react"; import FileSaver from "file-saver"; import { logger } from "matrix-js-sdk/src/logger"; import { AuthDict, CrossSigningKeys, MatrixError, UIAFlow, UIAResponse } from "matrix-js-sdk/src/matrix"; -import { CryptoEvent, BackupTrustInfo, GeneratedSecretStorageKey, KeyBackupInfo } from "matrix-js-sdk/src/crypto-api"; +import { GeneratedSecretStorageKey } from "matrix-js-sdk/src/crypto-api"; import classNames from "classnames"; import CheckmarkIcon from "@vector-im/compound-design-tokens/assets/web/icons/check"; @@ -25,7 +25,6 @@ import StyledRadioButton from "../../../../components/views/elements/StyledRadio import AccessibleButton from "../../../../components/views/elements/AccessibleButton"; import DialogButtons from "../../../../components/views/elements/DialogButtons"; import InlineSpinner from "../../../../components/views/elements/InlineSpinner"; -import RestoreKeyBackupDialog from "../../../../components/views/dialogs/security/RestoreKeyBackupDialog"; import { getSecureBackupSetupMethods, isSecureBackupRequired, @@ -45,7 +44,6 @@ enum Phase { Loading = "loading", LoadError = "load_error", ChooseKeyPassphrase = "choose_key_passphrase", - Migrate = "migrate", Passphrase = "passphrase", PassphraseConfirm = "passphrase_confirm", ShowKey = "show_key", @@ -72,24 +70,6 @@ interface IState { downloaded: boolean; setPassphrase: boolean; - /** Information on the current key backup version, as returned by the server. - * - * `null` could mean any of: - * * we haven't yet requested the data from the server. - * * we were unable to reach the server. - * * the server returned key backup version data we didn't understand or was malformed. - * * there is actually no backup on the server. - */ - backupInfo: KeyBackupInfo | null; - - /** - * Information on whether the backup in `backupInfo` is correctly signed, and whether we have the right key to - * decrypt it. - * - * `undefined` if `backupInfo` is null, or if crypto is not enabled in the client. - */ - backupTrustInfo: BackupTrustInfo | undefined; - // does the server offer a UI auth flow with just m.login.password // for /keys/device_signing/upload? canUploadKeysWithPasswordOnly: boolean | null; @@ -141,16 +121,17 @@ export default class CreateSecretStorageDialog extends React.PureComponent { - try { - const cli = MatrixClientPeg.safeGet(); - const backupInfo = await cli.getKeyBackupVersion(); - const backupTrustInfo = - // we may not have started crypto yet, in which case we definitely don't trust the backup - backupInfo ? await cli.getCrypto()?.isKeyBackupTrusted(backupInfo) : undefined; - - const { forceReset } = this.props; - const phase = backupInfo && !forceReset ? Phase.Migrate : Phase.ChooseKeyPassphrase; - - this.setState({ - phase, - backupInfo, - backupTrustInfo, - }); - - return backupTrustInfo; - } catch (e) { - console.error("Error fetching backup data from server", e); - this.setState({ phase: Phase.LoadError }); - return undefined; - } + private initExtension(keyFromCustomisations: Uint8Array): void { + logger.log("CryptoSetupExtension: Created key via extension, jumping to bootstrap step"); + this.recoveryKey = { + privateKey: keyFromCustomisations, + }; + this.bootstrapSecretStorage(); } private async queryKeyUploadAuth(): Promise { @@ -237,10 +173,6 @@ export default class CreateSecretStorageDialog extends React.PureComponent { - if (this.state.phase === Phase.Migrate) this.fetchBackupInfo(); - }; - private onKeyPassphraseChange = (e: React.ChangeEvent): void => { this.setState({ passPhraseKeySelected: e.target.value, @@ -265,15 +197,6 @@ export default class CreateSecretStorageDialog extends React.PureComponent { - e.preventDefault(); - if (this.state.backupTrustInfo?.trusted) { - this.bootstrapSecretStorage(); - } else { - this.restoreBackup(); - } - }; - private onCopyClick = (): void => { const successful = copyNode(this.recoveryKeyNode.current); if (successful) { @@ -340,16 +263,28 @@ export default class CreateSecretStorageDialog extends React.PureComponent => { + const cli = MatrixClientPeg.safeGet(); + const crypto = cli.getCrypto()!; + const { forceReset } = this.props; + + let backupInfo; + // First, unless we know we want to do a reset, we see if there is an existing key backup + if (!forceReset) { + try { + this.setState({ phase: Phase.Loading }); + backupInfo = await cli.getKeyBackupVersion(); + } catch (e) { + logger.error("Error fetching backup data from server", e); + this.setState({ phase: Phase.LoadError }); + return; + } + } + this.setState({ phase: Phase.Storing, error: undefined, }); - const cli = MatrixClientPeg.safeGet(); - const crypto = cli.getCrypto()!; - - const { forceReset } = this.props; - try { if (forceReset) { logger.log("Forcing secret storage reset"); @@ -371,8 +306,7 @@ export default class CreateSecretStorageDialog extends React.PureComponent this.recoveryKey!, - keyBackupInfo: this.state.backupInfo!, - setupNewKeyBackup: !this.state.backupInfo, + setupNewKeyBackup: !backupInfo, }); } await initialiseDehydration(true); @@ -381,20 +315,7 @@ export default class CreateSecretStorageDialog extends React.PureComponent => { - const { finished } = Modal.createDialog( - RestoreKeyBackupDialog, - { - showSummary: false, - }, - undefined, - /* priority = */ false, - /* static = */ false, - ); - - await finished; - const backupTrustInfo = await this.fetchBackupInfo(); - if (backupTrustInfo?.trusted && this.state.canUploadKeysWithPasswordOnly && this.state.accountPassword) { - this.bootstrapSecretStorage(); - } - }; - private onLoadRetryClick = (): void => { - this.setState({ phase: Phase.Loading }); - this.fetchBackupInfo(); + this.bootstrapSecretStorage(); }; private onShowKeyContinueClick = (): void => { @@ -495,12 +397,6 @@ export default class CreateSecretStorageDialog extends React.PureComponent): void => { - this.setState({ - accountPassword: e.target.value, - }); - }; - private renderOptionKey(): JSX.Element { return ( -
{_t("settings|key_backup|setup_secure_backup|requires_password_confirmation")}
-
- -
- - ); - } else if (!this.state.backupTrustInfo?.trusted) { - authPrompt = ( -
-
{_t("settings|key_backup|setup_secure_backup|requires_key_restore")}
-
- ); - nextCaption = _t("action|restore"); - } else { - authPrompt =

{_t("settings|key_backup|setup_secure_backup|requires_server_authentication")}

; - } - - return ( -
-

{_t("settings|key_backup|setup_secure_backup|session_upgrade_description")}

-
{authPrompt}
- - - -
- ); - } - private renderPhasePassPhrase(): JSX.Element { return (
@@ -829,8 +676,6 @@ export default class CreateSecretStorageDialog extends React.PureComponent { private unmounted = true; private image = createRef(); + private placeholder = createRef(); private timeout?: number; private sizeWatcher?: string; @@ -453,7 +454,11 @@ export default class MImageBody extends React.Component { "mx_MImageBody_placeholder--blurhash": this.props.mxEvent.getContent().info?.[BLURHASH_FIELD], }); - placeholder =
{this.getPlaceholder(maxWidth, maxHeight)}
; + placeholder = ( +
+ {this.getPlaceholder(maxWidth, maxHeight)} +
+ ); } let showPlaceholder = Boolean(placeholder); @@ -499,8 +504,19 @@ export default class MImageBody extends React.Component { if (!this.props.forExport) { placeholder = ( - - {showPlaceholder ? placeholder : <> /* Transition always expects a child */} + + { + showPlaceholder ? ( + placeholder + ) : ( +
+ ) /* Transition always expects a child */ + } ); diff --git a/src/components/views/rooms/RoomBreadcrumbs.tsx b/src/components/views/rooms/RoomBreadcrumbs.tsx index 19405e96b0..5de4687cb9 100644 --- a/src/components/views/rooms/RoomBreadcrumbs.tsx +++ b/src/components/views/rooms/RoomBreadcrumbs.tsx @@ -6,7 +6,7 @@ SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only Please see LICENSE files in the repository root for full details. */ -import React from "react"; +import React, { createRef } from "react"; import { Room } from "matrix-js-sdk/src/matrix"; import { CSSTransition } from "react-transition-group"; @@ -61,6 +61,7 @@ const RoomBreadcrumbTile: React.FC<{ room: Room; onClick: (ev: ButtonEvent) => v export default class RoomBreadcrumbs extends React.PureComponent { private isMounted = true; + private toolbar = createRef(); public constructor(props: IProps) { super(props); @@ -113,8 +114,18 @@ export default class RoomBreadcrumbs extends React.PureComponent if (tiles.length > 0) { // NOTE: The CSSTransition timeout MUST match the timeout in our CSS! return ( - - + + {tiles.slice(this.state.skipFirst ? 1 : 0)} diff --git a/src/components/views/rooms/RoomHeader.tsx b/src/components/views/rooms/RoomHeader.tsx index e47a785779..fc6fbcffa7 100644 --- a/src/components/views/rooms/RoomHeader.tsx +++ b/src/components/views/rooms/RoomHeader.tsx @@ -27,7 +27,7 @@ import { useRoomMemberCount, useRoomMembers } from "../../../hooks/useRoomMember import { _t } from "../../../languageHandler"; import { Flex } from "../../utils/Flex"; import { Box } from "../../utils/Box"; -import { getPlatformCallTypeLabel, useRoomCall } from "../../../hooks/room/useRoomCall"; +import { getPlatformCallTypeChildren, getPlatformCallTypeLabel, useRoomCall } from "../../../hooks/room/useRoomCall"; import { useRoomThreadNotifications } from "../../../hooks/room/useRoomThreadNotifications"; import { useGlobalNotificationState } from "../../../hooks/useGlobalNotificationState"; import SdkConfig from "../../../SdkConfig"; @@ -172,6 +172,8 @@ export default function RoomHeader({ key={option} label={getPlatformCallTypeLabel(option)} aria-label={getPlatformCallTypeLabel(option)} + children={getPlatformCallTypeChildren(option)} + className="mx_RoomHeader_videoCallOption" onClick={(ev) => videoCallClick(ev, option)} Icon={VideoCallIcon} onSelect={() => {} /* Dummy handler since we want the click event.*/} diff --git a/src/hooks/room/useRoomCall.ts b/src/hooks/room/useRoomCall.tsx similarity index 96% rename from src/hooks/room/useRoomCall.ts rename to src/hooks/room/useRoomCall.tsx index adf16cc5cc..c7319b4e58 100644 --- a/src/hooks/room/useRoomCall.ts +++ b/src/hooks/room/useRoomCall.tsx @@ -7,7 +7,7 @@ Please see LICENSE files in the repository root for full details. */ import { Room } from "matrix-js-sdk/src/matrix"; -import React, { useCallback, useEffect, useMemo, useState } from "react"; +import React, { ReactNode, useCallback, useEffect, useMemo, useState } from "react"; import { CallType } from "matrix-js-sdk/src/webrtc/call"; import { useFeatureEnabled } from "../useSettings"; @@ -35,6 +35,7 @@ import { isVideoRoom } from "../../utils/video-rooms"; import { useGuestAccessInformation } from "./useGuestAccessInformation"; import SettingsStore from "../../settings/SettingsStore"; import { UIFeature } from "../../settings/UIFeature"; +import { BetaPill } from "../../components/views/beta/BetaCard"; export enum PlatformCallType { ElementCall, @@ -51,6 +52,14 @@ export const getPlatformCallTypeLabel = (platformCallType: PlatformCallType): st return _t("voip|legacy_call"); } }; +export const getPlatformCallTypeChildren = (platformCallType: PlatformCallType): ReactNode => { + switch (platformCallType) { + case PlatformCallType.ElementCall: + return ; + default: + return null; + } +}; const enum State { NoCall, NoOneHere, diff --git a/src/i18n/strings/en_EN.json b/src/i18n/strings/en_EN.json index 77d2e79be1..f31af3983a 100644 --- a/src/i18n/strings/en_EN.json +++ b/src/i18n/strings/en_EN.json @@ -103,7 +103,6 @@ "report_content": "Report Content", "resend": "Resend", "reset": "Reset", - "restore": "Restore", "resume": "Resume", "retry": "Retry", "review": "Review", @@ -930,7 +929,6 @@ }, "unable_to_setup_keys_error": "Unable to set up keys", "unsupported": "This client does not support end-to-end encryption.", - "upgrade_toast_title": "Encryption upgrade available", "verification": { "accepting": "Accepting…", "after_new_login": { @@ -2594,18 +2592,13 @@ "pass_phrase_match_failed": "That doesn't match.", "pass_phrase_match_success": "That matches!", "phrase_strong_enough": "Great! This Security Phrase looks strong enough.", - "requires_key_restore": "Restore your key backup to upgrade your encryption", - "requires_password_confirmation": "Enter your account password to confirm the upgrade:", - "requires_server_authentication": "You'll need to authenticate with the server to confirm the upgrade.", "secret_storage_query_failure": "Unable to query secret storage status", "security_key_safety_reminder": "Store your Security Key somewhere safe, like a password manager or a safe, as it's used to safeguard your encrypted data.", - "session_upgrade_description": "Upgrade this session to allow it to verify other sessions, granting them access to encrypted messages and marking them as trusted for other users.", "set_phrase_again": "Go back to set it again.", "settings_reminder": "You can also set up Secure Backup & manage your keys in Settings.", "title_confirm_phrase": "Confirm Security Phrase", "title_save_key": "Save your Security Key", "title_set_phrase": "Set a Security Phrase", - "title_upgrade_encryption": "Upgrade your encryption", "unable_to_setup": "Unable to set up secret storage", "use_different_passphrase": "Use a different passphrase?", "use_phrase_only_you_know": "Use a secret phrase only you know, and optionally save a Security Key to use for backup." diff --git a/src/stores/widgets/StopGapWidgetDriver.ts b/src/stores/widgets/StopGapWidgetDriver.ts index b5609dc5fb..07fca154e8 100644 --- a/src/stores/widgets/StopGapWidgetDriver.ts +++ b/src/stores/widgets/StopGapWidgetDriver.ts @@ -416,26 +416,54 @@ export class StopGapWidgetDriver extends WidgetDriver { /** * Implements {@link WidgetDriver#sendToDevice} - * Encrypted to-device events are not supported. */ public async sendToDevice( eventType: string, encrypted: boolean, contentMap: { [userId: string]: { [deviceId: string]: object } }, ): Promise { - if (encrypted) throw new Error("Encrypted to-device events are not supported"); - const client = MatrixClientPeg.safeGet(); - await client.queueToDevice({ - eventType, - batch: Object.entries(contentMap).flatMap(([userId, userContentMap]) => - Object.entries(userContentMap).map(([deviceId, content]) => ({ - userId, - deviceId, - payload: content, - })), - ), - }); + + if (encrypted) { + const crypto = client.getCrypto(); + if (!crypto) throw new Error("E2EE not enabled"); + + // attempt to re-batch these up into a single request + const invertedContentMap: { [content: string]: { userId: string; deviceId: string }[] } = {}; + + for (const userId of Object.keys(contentMap)) { + const userContentMap = contentMap[userId]; + for (const deviceId of Object.keys(userContentMap)) { + const content = userContentMap[deviceId]; + const stringifiedContent = JSON.stringify(content); + invertedContentMap[stringifiedContent] = invertedContentMap[stringifiedContent] || []; + invertedContentMap[stringifiedContent].push({ userId, deviceId }); + } + } + + await Promise.all( + Object.entries(invertedContentMap).map(async ([stringifiedContent, recipients]) => { + const batch = await crypto.encryptToDeviceMessages( + eventType, + recipients, + JSON.parse(stringifiedContent), + ); + + await client.queueToDevice(batch); + }), + ); + } else { + await client.queueToDevice({ + eventType, + batch: Object.entries(contentMap).flatMap(([userId, userContentMap]) => + Object.entries(userContentMap).map(([deviceId, content]) => ({ + userId, + deviceId, + payload: content, + })), + ), + }); + } } private pickRooms(roomIds?: (string | Symbols.AnyRoom)[]): Room[] { diff --git a/src/toasts/SetupEncryptionToast.ts b/src/toasts/SetupEncryptionToast.ts index 39408ba7f7..0dd54bb18f 100644 --- a/src/toasts/SetupEncryptionToast.ts +++ b/src/toasts/SetupEncryptionToast.ts @@ -23,8 +23,6 @@ const getTitle = (kind: Kind): string => { switch (kind) { case Kind.SET_UP_ENCRYPTION: return _t("encryption|set_up_toast_title"); - case Kind.UPGRADE_ENCRYPTION: - return _t("encryption|upgrade_toast_title"); case Kind.VERIFY_THIS_SESSION: return _t("encryption|verify_toast_title"); } @@ -33,7 +31,6 @@ const getTitle = (kind: Kind): string => { const getIcon = (kind: Kind): string => { switch (kind) { case Kind.SET_UP_ENCRYPTION: - case Kind.UPGRADE_ENCRYPTION: return "secure_backup"; case Kind.VERIFY_THIS_SESSION: return "verification_warning"; @@ -44,8 +41,6 @@ const getSetupCaption = (kind: Kind): string => { switch (kind) { case Kind.SET_UP_ENCRYPTION: return _t("action|continue"); - case Kind.UPGRADE_ENCRYPTION: - return _t("action|upgrade"); case Kind.VERIFY_THIS_SESSION: return _t("action|verify"); } @@ -54,7 +49,6 @@ const getSetupCaption = (kind: Kind): string => { const getDescription = (kind: Kind): string => { switch (kind) { case Kind.SET_UP_ENCRYPTION: - case Kind.UPGRADE_ENCRYPTION: return _t("encryption|set_up_toast_description"); case Kind.VERIFY_THIS_SESSION: return _t("encryption|verify_toast_description"); @@ -63,7 +57,6 @@ const getDescription = (kind: Kind): string => { export enum Kind { SET_UP_ENCRYPTION = "set_up_encryption", - UPGRADE_ENCRYPTION = "upgrade_encryption", VERIFY_THIS_SESSION = "verify_this_session", } diff --git a/src/utils/exportUtils/HtmlExport.tsx b/src/utils/exportUtils/HtmlExport.tsx index 08e488e5ff..2870ccafd3 100644 --- a/src/utils/exportUtils/HtmlExport.tsx +++ b/src/utils/exportUtils/HtmlExport.tsx @@ -161,24 +161,19 @@ export default class HTMLExporter extends Exporter {
-
-
-
-
- ${roomAvatar} +
+ ${roomAvatar} +
+
+ + ${safeRoomName} + +
-
-
-
- ${safeRoomName} -
-
-
${safeTopic}
-
${previousMessagesLink}
diff --git a/src/utils/exportUtils/exportCustomCSS.css b/src/utils/exportUtils/exportCustomCSS.css index 3d034d7df5..b3fa8e81d3 100644 --- a/src/utils/exportUtils/exportCustomCSS.css +++ b/src/utils/exportUtils/exportCustomCSS.css @@ -130,6 +130,14 @@ a.mx_reply_anchor:hover { } } +.mx_RoomHeader { + --mx-flex-display: flex; + --mx-flex-direction: row; + --mx-flex-align: center; + --mx-flex-justify: start; + --mx-flex-gap: var(--cpd-space-3x); +} + .mx_ReplyChain_Export { margin-top: 0; margin-bottom: 5px; diff --git a/test/test-utils/test-utils.ts b/test/test-utils/test-utils.ts index c36b1f5054..0e608b1426 100644 --- a/test/test-utils/test-utils.ts +++ b/test/test-utils/test-utils.ts @@ -127,6 +127,10 @@ export function createTestClient(): MatrixClient { prepareToEncrypt: jest.fn(), bootstrapCrossSigning: jest.fn(), getActiveSessionBackupVersion: jest.fn().mockResolvedValue(null), + isKeyBackupTrusted: jest.fn().mockResolvedValue({}), + createRecoveryKeyFromPassphrase: jest.fn().mockResolvedValue({}), + bootstrapSecretStorage: jest.fn(), + isDehydrationSupported: jest.fn().mockResolvedValue(false), }), getPushActionsForEvent: jest.fn(), @@ -270,6 +274,7 @@ export function createTestClient(): MatrixClient { getOrCreateFilter: jest.fn(), sendStickerMessage: jest.fn(), getLocalAliases: jest.fn().mockReturnValue([]), + uploadDeviceSigningKeys: jest.fn(), } as unknown as MatrixClient; client.reEmitter = new ReEmitter(client); diff --git a/test/unit-tests/DecryptionFailureTracker-test.ts b/test/unit-tests/DecryptionFailureTracker-test.ts index b7884076ae..898816923f 100644 --- a/test/unit-tests/DecryptionFailureTracker-test.ts +++ b/test/unit-tests/DecryptionFailureTracker-test.ts @@ -496,6 +496,8 @@ describe("DecryptionFailureTracker", function () { await createAndTrackEventWithError(DecryptionFailureCode.HISTORICAL_MESSAGE_USER_NOT_JOINED); await createAndTrackEventWithError(DecryptionFailureCode.MEGOLM_KEY_WITHHELD); await createAndTrackEventWithError(DecryptionFailureCode.MEGOLM_KEY_WITHHELD_FOR_UNVERIFIED_DEVICE); + await createAndTrackEventWithError(DecryptionFailureCode.SENDER_IDENTITY_PREVIOUSLY_VERIFIED); + await createAndTrackEventWithError(DecryptionFailureCode.UNSIGNED_SENDER_DEVICE); await createAndTrackEventWithError(DecryptionFailureCode.UNKNOWN_ERROR); // Pretend "now" is Infinity @@ -510,6 +512,8 @@ describe("DecryptionFailureTracker", function () { "ExpectedDueToMembership", "OlmKeysNotSentError", "RoomKeysWithheldForUnverifiedDevice", + "ExpectedVerificationViolation", + "ExpectedSentByInsecureDevice", "UnknownError", ]); }); diff --git a/test/unit-tests/DeviceListener-test.ts b/test/unit-tests/DeviceListener-test.ts index 64761d7da1..0f3bb68254 100644 --- a/test/unit-tests/DeviceListener-test.ts +++ b/test/unit-tests/DeviceListener-test.ts @@ -351,13 +351,13 @@ describe("DeviceListener", () => { mockCrypto!.getCrossSigningKeyId.mockResolvedValue("abc"); }); - it("shows upgrade encryption toast when user has a key backup available", async () => { + it("shows set up encryption toast when user has a key backup available", async () => { // non falsy response mockClient!.getKeyBackupVersion.mockResolvedValue({} as unknown as KeyBackupInfo); await createAndStart(); expect(SetupEncryptionToast.showToast).toHaveBeenCalledWith( - SetupEncryptionToast.Kind.UPGRADE_ENCRYPTION, + SetupEncryptionToast.Kind.SET_UP_ENCRYPTION, ); }); }); diff --git a/test/unit-tests/components/views/dialogs/security/CreateSecretStorageDialog-test.tsx b/test/unit-tests/components/views/dialogs/security/CreateSecretStorageDialog-test.tsx index 5d1bbb4602..b9d0514148 100644 --- a/test/unit-tests/components/views/dialogs/security/CreateSecretStorageDialog-test.tsx +++ b/test/unit-tests/components/views/dialogs/security/CreateSecretStorageDialog-test.tsx @@ -10,42 +10,23 @@ import { render, RenderResult, screen } from "jest-matrix-react"; import userEvent from "@testing-library/user-event"; import React from "react"; import { mocked, MockedObject } from "jest-mock"; -import { Crypto, MatrixClient, MatrixError } from "matrix-js-sdk/src/matrix"; -import { defer, IDeferred, sleep } from "matrix-js-sdk/src/utils"; -import { BackupTrustInfo, KeyBackupInfo } from "matrix-js-sdk/src/crypto-api"; +import { MatrixClient, MatrixError } from "matrix-js-sdk/src/matrix"; +import { sleep } from "matrix-js-sdk/src/utils"; -import { - filterConsole, - flushPromises, - getMockClientWithEventEmitter, - mockClientMethodsCrypto, - mockClientMethodsServer, -} from "../../../../../test-utils"; +import { filterConsole, stubClient } from "../../../../../test-utils"; import CreateSecretStorageDialog from "../../../../../../src/async-components/views/dialogs/security/CreateSecretStorageDialog"; -import Modal from "../../../../../../src/Modal"; -import RestoreKeyBackupDialog from "../../../../../../src/components/views/dialogs/security/RestoreKeyBackupDialog"; describe("CreateSecretStorageDialog", () => { let mockClient: MockedObject; - let mockCrypto: MockedObject; beforeEach(() => { - mockClient = getMockClientWithEventEmitter({ - ...mockClientMethodsServer(), - ...mockClientMethodsCrypto(), - uploadDeviceSigningKeys: jest.fn().mockImplementation(async () => { - await sleep(0); // CreateSecretStorageDialog doesn't expect this to resolve immediately - throw new MatrixError({ flows: [] }); - }), - }); - - mockCrypto = mocked(mockClient.getCrypto()!); - Object.assign(mockCrypto, { - isKeyBackupTrusted: jest.fn(), - isDehydrationSupported: jest.fn(() => false), - bootstrapCrossSigning: jest.fn(), - bootstrapSecretStorage: jest.fn(), + mockClient = mocked(stubClient()); + mockClient.uploadDeviceSigningKeys.mockImplementation(async () => { + await sleep(0); // CreateSecretStorageDialog doesn't expect this to resolve immediately + throw new MatrixError({ flows: [] }); }); + // Mock the clipboard API + document.execCommand = jest.fn().mockReturnValue(true); }); afterEach(() => { @@ -59,11 +40,37 @@ describe("CreateSecretStorageDialog", () => { return render(); } - it("shows a loading spinner initially", async () => { - const { container } = renderComponent(); - expect(screen.getByTestId("spinner")).toBeDefined(); - expect(container).toMatchSnapshot(); - await flushPromises(); + it("handles the happy path", async () => { + const result = renderComponent(); + await result.findByText( + "Safeguard against losing access to encrypted messages & data by backing up encryption keys on your server.", + ); + expect(result.container).toMatchSnapshot(); + await userEvent.click(result.getByRole("button", { name: "Continue" })); + + await screen.findByText("Save your Security Key"); + expect(result.container).toMatchSnapshot(); + // Copy the key to enable the continue button + await userEvent.click(screen.getByRole("button", { name: "Copy" })); + expect(result.queryByText("Copied!")).not.toBeNull(); + await userEvent.click(screen.getByRole("button", { name: "Continue" })); + + await screen.findByText("Your keys are now being backed up from this device."); + }); + + it("when there is an error when bootstraping the secret storage, it shows an error", async () => { + jest.spyOn(mockClient.getCrypto()!, "bootstrapSecretStorage").mockRejectedValue(new Error("error")); + + renderComponent(); + await screen.findByText( + "Safeguard against losing access to encrypted messages & data by backing up encryption keys on your server.", + ); + await userEvent.click(screen.getByRole("button", { name: "Continue" })); + await screen.findByText("Save your Security Key"); + await userEvent.click(screen.getByRole("button", { name: "Copy" })); + await userEvent.click(screen.getByRole("button", { name: "Continue" })); + + await screen.findByText("Unable to set up secret storage"); }); describe("when there is an error fetching the backup version", () => { @@ -75,139 +82,19 @@ describe("CreateSecretStorageDialog", () => { }); const result = renderComponent(); + // We go though the dialog until we have to get the key backup + await userEvent.click(result.getByRole("button", { name: "Continue" })); + await userEvent.click(screen.getByRole("button", { name: "Copy" })); + await userEvent.click(screen.getByRole("button", { name: "Continue" })); + // XXX the error message is... misleading. - await result.findByText("Unable to query secret storage status"); - expect(result.container).toMatchSnapshot(); - }); - }); - - it("shows 'Generate a Security Key' text if no key backup is present", async () => { - const result = renderComponent(); - await flushPromises(); - expect(result.container).toMatchSnapshot(); - result.getByText("Generate a Security Key"); - }); - - describe("when canUploadKeysWithPasswordOnly", () => { - // spy on Modal.createDialog - let modalSpy: jest.SpyInstance; - - // deferred which should be resolved to indicate that the created dialog has completed - let restoreDialogFinishedDefer: IDeferred<[done?: boolean]>; - - beforeEach(() => { - mockClient.getKeyBackupVersion.mockResolvedValue({} as KeyBackupInfo); - mockClient.uploadDeviceSigningKeys.mockImplementation(async () => { - await sleep(0); - throw new MatrixError({ - flows: [{ stages: ["m.login.password"] }], - }); - }); - - restoreDialogFinishedDefer = defer<[done?: boolean]>(); - modalSpy = jest.spyOn(Modal, "createDialog").mockReturnValue({ - finished: restoreDialogFinishedDefer.promise, - close: jest.fn(), - }); - }); - - it("prompts for a password and then shows RestoreKeyBackupDialog", async () => { - const result = renderComponent(); - await result.findByText(/Enter your account password to confirm the upgrade/); + await screen.findByText("Unable to query secret storage status"); expect(result.container).toMatchSnapshot(); - await userEvent.type(result.getByPlaceholderText("Password"), "my pass"); - result.getByRole("button", { name: "Next" }).click(); - - expect(modalSpy).toHaveBeenCalledWith( - RestoreKeyBackupDialog, - { - showSummary: false, - }, - undefined, - false, - false, - ); - - restoreDialogFinishedDefer.resolve([]); - }); - - it("calls bootstrapSecretStorage once keys are restored if the backup is now trusted", async () => { - const result = renderComponent(); - await result.findByText(/Enter your account password to confirm the upgrade/); - expect(result.container).toMatchSnapshot(); - - await userEvent.type(result.getByPlaceholderText("Password"), "my pass"); - result.getByRole("button", { name: "Next" }).click(); - - expect(modalSpy).toHaveBeenCalled(); - - // While we restore the key backup, its signature becomes accepted - mockCrypto.isKeyBackupTrusted.mockResolvedValue({ trusted: true } as BackupTrustInfo); - - restoreDialogFinishedDefer.resolve([]); - await flushPromises(); - - // XXX no idea why this is a sensible thing to do. I just work here. - expect(mockCrypto.bootstrapCrossSigning).toHaveBeenCalled(); - expect(mockCrypto.bootstrapSecretStorage).toHaveBeenCalled(); - - await result.findByText("Your keys are now being backed up from this device."); - }); - - describe("when there is an error fetching the backup version after RestoreKeyBackupDialog", () => { - filterConsole("Error fetching backup data from server"); - - it("handles the error sensibly", async () => { - const result = renderComponent(); - await result.findByText(/Enter your account password to confirm the upgrade/); - expect(result.container).toMatchSnapshot(); - - await userEvent.type(result.getByPlaceholderText("Password"), "my pass"); - result.getByRole("button", { name: "Next" }).click(); - - expect(modalSpy).toHaveBeenCalled(); - - mockClient.getKeyBackupVersion.mockImplementation(async () => { - throw new Error("bleh bleh"); - }); - restoreDialogFinishedDefer.resolve([]); - await result.findByText("Unable to query secret storage status"); - }); - }); - }); - - describe("when backup is present but not trusted", () => { - beforeEach(() => { - mockClient.getKeyBackupVersion.mockResolvedValue({} as KeyBackupInfo); - }); - - it("shows migrate text, then 'RestoreKeyBackupDialog' if 'Restore' is clicked", async () => { - const result = renderComponent(); - await result.findByText("Restore your key backup to upgrade your encryption"); - expect(result.container).toMatchSnapshot(); - - // before we click "Restore", set up a spy on createDialog - const restoreDialogFinishedDefer = defer<[done?: boolean]>(); - const modalSpy = jest.spyOn(Modal, "createDialog").mockReturnValue({ - finished: restoreDialogFinishedDefer.promise, - close: jest.fn(), - }); - - result.getByRole("button", { name: "Restore" }).click(); - - expect(modalSpy).toHaveBeenCalledWith( - RestoreKeyBackupDialog, - { - showSummary: false, - }, - undefined, - false, - false, - ); - - // simulate RestoreKeyBackupDialog completing, to run that code path - restoreDialogFinishedDefer.resolve([]); + // Now we can get the backup and we retry + mockClient.getKeyBackupVersion.mockRestore(); + await userEvent.click(screen.getByRole("button", { name: "Retry" })); + await screen.findByText("Your keys are now being backed up from this device."); }); }); }); diff --git a/test/unit-tests/components/views/dialogs/security/__snapshots__/CreateSecretStorageDialog-test.tsx.snap b/test/unit-tests/components/views/dialogs/security/__snapshots__/CreateSecretStorageDialog-test.tsx.snap index 3ba1018ae1..5ad3590422 100644 --- a/test/unit-tests/components/views/dialogs/security/__snapshots__/CreateSecretStorageDialog-test.tsx.snap +++ b/test/unit-tests/components/views/dialogs/security/__snapshots__/CreateSecretStorageDialog-test.tsx.snap @@ -1,6 +1,6 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP -exports[`CreateSecretStorageDialog shows 'Generate a Security Key' text if no key backup is present 1`] = ` +exports[`CreateSecretStorageDialog handles the happy path 1`] = `
`; -exports[`CreateSecretStorageDialog shows a loading spinner initially 1`] = ` +exports[`CreateSecretStorageDialog handles the happy path 2`] = `
+ > +

+ Save your Security Key +

+
+

+ Store your Security Key somewhere safe, like a password manager or a safe, as it's used to safeguard your encrypted data. +

+ class="mx_CreateSecretStorageDialog_recoveryKeyContainer" + > +
+ +
+
+
+ Download +
+ + or + +
+ Copy +
+
+
+
+
+ + +
@@ -168,331 +217,6 @@ exports[`CreateSecretStorageDialog shows a loading spinner initially 1`] = `
`; -exports[`CreateSecretStorageDialog when backup is present but not trusted shows migrate text, then 'RestoreKeyBackupDialog' if 'Restore' is clicked 1`] = ` -
-
- -
-
-`; - -exports[`CreateSecretStorageDialog when canUploadKeysWithPasswordOnly calls bootstrapSecretStorage once keys are restored if the backup is now trusted 1`] = ` -
-
- -
-
-`; - -exports[`CreateSecretStorageDialog when canUploadKeysWithPasswordOnly prompts for a password and then shows RestoreKeyBackupDialog 1`] = ` -
-
- -
-
-`; - -exports[`CreateSecretStorageDialog when canUploadKeysWithPasswordOnly when there is an error fetching the backup version after RestoreKeyBackupDialog handles the error sensibly 1`] = ` -
-
- -
-
-`; - exports[`CreateSecretStorageDialog when there is an error fetching the backup version shows an error 1`] = `
{ }); }); - it("raises an error if encrypted", async () => { - await expect(driver.sendToDevice("org.example.foo", true, contentMap)).rejects.toThrow( - "Encrypted to-device events are not supported", + it("sends encrypted messages", async () => { + const encryptToDeviceMessages = jest + .fn() + .mockImplementation( + (eventType, recipients: { userId: string; deviceId: string }[], content: object) => ({ + eventType: "m.room.encrypted", + batch: recipients.map(({ userId, deviceId }) => ({ + userId, + deviceId, + payload: { + eventType, + content, + }, + })), + }), + ); + + MatrixClientPeg.safeGet().getCrypto()!.encryptToDeviceMessages = encryptToDeviceMessages; + + await driver.sendToDevice("org.example.foo", true, { + "@alice:example.org": { + aliceMobile: { + hello: "alice", + }, + }, + "@bob:example.org": { + bobDesktop: { + hello: "bob", + }, + }, + }); + + expect(encryptToDeviceMessages).toHaveBeenCalledWith( + "org.example.foo", + [{ deviceId: "aliceMobile", userId: "@alice:example.org" }], + { + hello: "alice", + }, ); + expect(encryptToDeviceMessages).toHaveBeenCalledWith( + "org.example.foo", + [{ deviceId: "bobDesktop", userId: "@bob:example.org" }], + { + hello: "bob", + }, + ); + expect(client.queueToDevice).toHaveBeenCalledWith({ + eventType: "m.room.encrypted", + batch: expect.arrayContaining([ + { + deviceId: "aliceMobile", + payload: { content: { hello: "alice" }, eventType: "org.example.foo" }, + userId: "@alice:example.org", + }, + ]), + }); + expect(client.queueToDevice).toHaveBeenCalledWith({ + eventType: "m.room.encrypted", + batch: expect.arrayContaining([ + { + deviceId: "bobDesktop", + payload: { content: { hello: "bob" }, eventType: "org.example.foo" }, + userId: "@bob:example.org", + }, + ]), + }); }); }); diff --git a/test/unit-tests/utils/exportUtils/__snapshots__/HTMLExport-test.ts.snap b/test/unit-tests/utils/exportUtils/__snapshots__/HTMLExport-test.ts.snap index 6a7adbabb2..94f31f7652 100644 --- a/test/unit-tests/utils/exportUtils/__snapshots__/HTMLExport-test.ts.snap +++ b/test/unit-tests/utils/exportUtils/__snapshots__/HTMLExport-test.ts.snap @@ -17,24 +17,19 @@ exports[`HTMLExport should export 1`] = `
-
-
-
-
- ! +
+ ! +
+
+ + !myroom:example.org + +
-
-
-
- !myroom:example.org -
-
-
-
diff --git a/yarn.lock b/yarn.lock index abaa6cc782..dee966cb86 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1421,14 +1421,26 @@ resolved "https://registry.yarnpkg.com/@dual-bundle/import-meta-resolve/-/import-meta-resolve-4.1.0.tgz#519c1549b0e147759e7825701ecffd25e5819f7b" integrity sha512-+nxncfwHM5SgAtrVzgpzJOI1ol0PkumhVo469KCf9lUi21IGcY90G98VuHm9VRrUypmAzawAHO9bs6hqeADaVg== -"@eslint-community/eslint-utils@^4.2.0", "@eslint-community/eslint-utils@^4.4.0": +"@eslint-community/eslint-utils@^4.2.0": version "4.4.0" resolved "https://registry.yarnpkg.com/@eslint-community/eslint-utils/-/eslint-utils-4.4.0.tgz#a23514e8fb9af1269d5f7788aa556798d61c6b59" integrity sha512-1/sA4dwrzBAyeUoQ6oxahHKmrZvsnLCg4RfxW3ZFGGmQkSNQPFNLV9CUEFQP1x9EYXHTo5p6xdhZM1Ne9p/AfA== dependencies: eslint-visitor-keys "^3.3.0" -"@eslint-community/regexpp@^4.10.0", "@eslint-community/regexpp@^4.6.1": +"@eslint-community/eslint-utils@^4.4.0": + version "4.4.1" + resolved "https://registry.yarnpkg.com/@eslint-community/eslint-utils/-/eslint-utils-4.4.1.tgz#d1145bf2c20132d6400495d6df4bf59362fd9d56" + integrity sha512-s3O3waFUrMV8P/XaF/+ZTp1X9XBZW1a4B97ZnjQF2KYWaFD2A8KyFBsrsfSjEmjn3RGWAIuvlneuZm3CUK3jbA== + dependencies: + eslint-visitor-keys "^3.4.3" + +"@eslint-community/regexpp@^4.10.0": + version "4.12.1" + resolved "https://registry.yarnpkg.com/@eslint-community/regexpp/-/regexpp-4.12.1.tgz#cfc6cffe39df390a3841cde2abccf92eaa7ae0e0" + integrity sha512-CCZCDJuduB9OUkFkY2IgppNZMi2lBQgD2qzwXkEia16cge2pijY/aXi96CJMquDMn3nJdlPV1A5KrJEXwfLNzQ== + +"@eslint-community/regexpp@^4.6.1": version "4.11.1" resolved "https://registry.yarnpkg.com/@eslint-community/regexpp/-/regexpp-4.11.1.tgz#a547badfc719eb3e5f4b556325e542fbe9d7a18f" integrity sha512-m4DVN9ZqskZoLU5GlWZadwDnYo3vAEydiUayB9widCl9ffWx2IvPnp6n3on5rJmziJSw9Bv+Z3ChDVdMwXCY8Q== @@ -1504,37 +1516,37 @@ resolved "https://registry.yarnpkg.com/@floating-ui/utils/-/utils-0.2.8.tgz#21a907684723bbbaa5f0974cf7730bd797eb8e62" integrity sha512-kym7SodPp8/wloecOpcmSnWJsK7M0E5Wg8UcFA+uO4B9s5d0ywXOEro/8HM9x0rW+TljRzul/14UYz3TleT3ig== -"@formatjs/ecma402-abstract@2.2.0": - version "2.2.0" - resolved "https://registry.yarnpkg.com/@formatjs/ecma402-abstract/-/ecma402-abstract-2.2.0.tgz#36f5bc0dac4ca77ca429fe44bd95b32d5ccd98dd" - integrity sha512-IpM+ev1E4QLtstniOE29W1rqH9eTdx5hQdNL8pzrflMj/gogfaoONZqL83LUeQScHAvyMbpqP5C9MzNf+fFwhQ== - dependencies: - "@formatjs/fast-memoize" "2.2.1" - "@formatjs/intl-localematcher" "0.5.5" - tslib "^2.7.0" - -"@formatjs/fast-memoize@2.2.1": +"@formatjs/ecma402-abstract@2.2.1": version "2.2.1" - resolved "https://registry.yarnpkg.com/@formatjs/fast-memoize/-/fast-memoize-2.2.1.tgz#74575f18c6a789472517995ca9686e7a3f7c0b60" - integrity sha512-XS2RcOSyWxmUB7BUjj3mlPH0exsUzlf6QfhhijgI941WaJhVxXQ6mEWkdUFIdnKi3TuTYxRdelsgv3mjieIGIA== + resolved "https://registry.yarnpkg.com/@formatjs/ecma402-abstract/-/ecma402-abstract-2.2.1.tgz#2e62bc5c22b0e6a5e13bfec6aac15d3d403e1065" + integrity sha512-O4ywpkdJybrjFc9zyL8qK5aklleIAi5O4nYhBVJaOFtCkNrnU+lKFeJOFC48zpsZQmR8Aok2V79hGpHnzbmFpg== dependencies: - tslib "^2.7.0" + "@formatjs/fast-memoize" "2.2.2" + "@formatjs/intl-localematcher" "0.5.6" + tslib "2" -"@formatjs/intl-localematcher@0.5.5": - version "0.5.5" - resolved "https://registry.yarnpkg.com/@formatjs/intl-localematcher/-/intl-localematcher-0.5.5.tgz#b24f100f30658104d5f6db35b0b8d97235298681" - integrity sha512-t5tOGMgZ/i5+ALl2/offNqAQq/lfUnKLEw0mXQI4N4bqpedhrSE+fyKLpwnd22sK0dif6AV+ufQcTsKShB9J1g== +"@formatjs/fast-memoize@2.2.2": + version "2.2.2" + resolved "https://registry.yarnpkg.com/@formatjs/fast-memoize/-/fast-memoize-2.2.2.tgz#2409ec10f5f7d6c65f4c04e6c2d6cc56fa1e4cef" + integrity sha512-mzxZcS0g1pOzwZTslJOBTmLzDXseMLLvnh25ymRilCm8QLMObsQ7x/rj9GNrH0iUhZMlFisVOD6J1n6WQqpKPQ== dependencies: - tslib "^2.7.0" + tslib "2" + +"@formatjs/intl-localematcher@0.5.6": + version "0.5.6" + resolved "https://registry.yarnpkg.com/@formatjs/intl-localematcher/-/intl-localematcher-0.5.6.tgz#cd0cd99483673d3196a15b4e2c924cfda7f002f8" + integrity sha512-roz1+Ba5e23AHX6KUAWmLEyTRZegM5YDuxuvkHCyK3RJddf/UXB2f+s7pOMm9ktfPGla0g+mQXOn5vsuYirnaA== + dependencies: + tslib "2" "@formatjs/intl-segmenter@^11.5.7": - version "11.5.9" - resolved "https://registry.yarnpkg.com/@formatjs/intl-segmenter/-/intl-segmenter-11.5.9.tgz#197aae6991d456cc28827928ed10db0f284c5e2a" - integrity sha512-/vRTJsue3GWk+jvf0VJao9xL+/sIykoMwTBzbq1UWGiyIcUdI4P+02KRbXCURgHovy2Ew7zkV7p8MYjTw8lrMw== + version "11.7.1" + resolved "https://registry.yarnpkg.com/@formatjs/intl-segmenter/-/intl-segmenter-11.7.1.tgz#61f0654adb7eb48c4893ac3f882ed93a34580491" + integrity sha512-rlJ0C2wq+NSQEFW6Lp3jf0qIhGX6smfz14hMRR/DYCJwQHOR2idW4zuwqcn/CrEQxXTOxAV0f2+N9AdCPeH5QA== dependencies: - "@formatjs/ecma402-abstract" "2.2.0" - "@formatjs/intl-localematcher" "0.5.5" - tslib "^2.7.0" + "@formatjs/ecma402-abstract" "2.2.1" + "@formatjs/intl-localematcher" "0.5.6" + tslib "2" "@humanwhocodes/config-array@^0.13.0": version "0.13.0" @@ -1919,10 +1931,10 @@ resolved "https://registry.yarnpkg.com/@mapbox/whoots-js/-/whoots-js-3.1.0.tgz#497c67a1cef50d1a2459ba60f315e448d2ad87fe" integrity sha512-Es6WcD0nO5l+2BOQS4uLfNPYQaNDfbot3X1XUoloz+x0mPDS3eeORZJl06HXjwBG1fOGwCRnzK88LMdxKRrd6Q== -"@matrix-org/analytics-events@^0.26.0": - version "0.26.0" - resolved "https://registry.yarnpkg.com/@matrix-org/analytics-events/-/analytics-events-0.26.0.tgz#7c8f8f924d8313c87951a0e941640ef8ff78f3d6" - integrity sha512-cjKZBejajUG8wPhVygMkBTwTLdEn74luUP6g6RjCUqPR3RYIl3NVi58Zil8CWfRTILb4wVLCPpAvehgXJn1HnQ== +"@matrix-org/analytics-events@^0.28.0": + version "0.28.0" + resolved "https://registry.yarnpkg.com/@matrix-org/analytics-events/-/analytics-events-0.28.0.tgz#91f501bb25435b9418f785ca850ca858aa6efc76" + integrity sha512-RvvGBYzgJrk2wTRVGk2fWhGM1f69f6nBraRqTiuqlqE2eQd2hZ2onHyRhvhxJeKVC/oNBsvrupObqrrWowXsnQ== "@matrix-org/emojibase-bindings@^1.3.3": version "1.3.3" @@ -2015,11 +2027,11 @@ webcrypto-core "^1.8.0" "@playwright/test@^1.40.1": - version "1.48.1" - resolved "https://registry.yarnpkg.com/@playwright/test/-/test-1.48.1.tgz#343e710fcf2e559529e3ec8d7782e09f325b9396" - integrity sha512-s9RtWoxkOLmRJdw3oFvhFbs9OJS0BzrLUc8Hf6l2UdCNd1rqeEyD4BhCJkvzeEoD1FsK4mirsWwGerhVmYKtZg== + version "1.48.2" + resolved "https://registry.yarnpkg.com/@playwright/test/-/test-1.48.2.tgz#87dd40633f980872283404c8142a65744d3f13d6" + integrity sha512-54w1xCWfXuax7dz4W2M9uw0gDyh+ti/0K/MxcCUxChFh37kkdxPdfZDw5QBbuPUJHr1CiHJ1hXgSs+GgeQc5Zw== dependencies: - playwright "1.48.1" + playwright "1.48.2" "@polka/url@^1.0.0-next.24": version "1.0.0-next.28" @@ -2317,43 +2329,43 @@ resolved "https://registry.yarnpkg.com/@rtsao/scc/-/scc-1.1.0.tgz#927dd2fae9bc3361403ac2c7a00c32ddce9ad7e8" integrity sha512-zt6OdqaDoOnJ1ZYsCYGt9YmWzDXl4vQdKTyJev62gFhRGKdx7mcT54V9KIjg+d2wi9EXsPvAPKe7i7WjfVWB8g== -"@sentry-internal/browser-utils@8.34.0": - version "8.34.0" - resolved "https://registry.yarnpkg.com/@sentry-internal/browser-utils/-/browser-utils-8.34.0.tgz#36a50d503ad4ad51fce22e80670f8fd6fd195a27" - integrity sha512-4AcYOzPzD1tL5eSRQ/GpKv5enquZf4dMVUez99/Bh3va8qiJrNP55AcM7UzZ7WZLTqKygIYruJTU5Zu2SpEAPQ== +"@sentry-internal/browser-utils@8.35.0": + version "8.35.0" + resolved "https://registry.yarnpkg.com/@sentry-internal/browser-utils/-/browser-utils-8.35.0.tgz#92602f8dd2bb777af2994eb446cb3cf71bf0cfad" + integrity sha512-uj9nwERm7HIS13f/Q52hF/NUS5Al8Ma6jkgpfYGeppYvU0uSjPkwMogtqoJQNbOoZg973tV8qUScbcWY616wNA== dependencies: - "@sentry/core" "8.34.0" - "@sentry/types" "8.34.0" - "@sentry/utils" "8.34.0" + "@sentry/core" "8.35.0" + "@sentry/types" "8.35.0" + "@sentry/utils" "8.35.0" -"@sentry-internal/feedback@8.34.0": - version "8.34.0" - resolved "https://registry.yarnpkg.com/@sentry-internal/feedback/-/feedback-8.34.0.tgz#ff0db65c36f13665db99e3e22f2032bfdda98731" - integrity sha512-aYSM2KPUs0FLPxxbJCFSwCYG70VMzlT04xepD1Y/tTlPPOja/02tSv2tyOdZbv8Uw7xslZs3/8Lhj74oYcTBxw== +"@sentry-internal/feedback@8.35.0": + version "8.35.0" + resolved "https://registry.yarnpkg.com/@sentry-internal/feedback/-/feedback-8.35.0.tgz#b31fb7fbec8ecd9cc683948a0d1af2b87731b0a1" + integrity sha512-7bjSaUhL0bDArozre6EiIhhdWdT/1AWNWBC1Wc5w1IxEi5xF7nvF/FfvjQYrONQzZAI3HRxc45J2qhLUzHBmoQ== dependencies: - "@sentry/core" "8.34.0" - "@sentry/types" "8.34.0" - "@sentry/utils" "8.34.0" + "@sentry/core" "8.35.0" + "@sentry/types" "8.35.0" + "@sentry/utils" "8.35.0" -"@sentry-internal/replay-canvas@8.34.0": - version "8.34.0" - resolved "https://registry.yarnpkg.com/@sentry-internal/replay-canvas/-/replay-canvas-8.34.0.tgz#10acadaef74e982dee2b9842a3eb6fec73f032ed" - integrity sha512-x8KhZcCDpbKHqFOykYXiamX6x0LRxv6N1OJHoH+XCrMtiDBZr4Yo30d/MaS6rjmKGMtSRij30v+Uq+YWIgxUrg== +"@sentry-internal/replay-canvas@8.35.0": + version "8.35.0" + resolved "https://registry.yarnpkg.com/@sentry-internal/replay-canvas/-/replay-canvas-8.35.0.tgz#de7849e0d4212ee37a9225b1fc346188d9b05072" + integrity sha512-TUrH6Piv19kvHIiRyIuapLdnuwxk/Un/l1WDCQfq7mK9p1Pac0FkQ7Uufjp6zY3lyhDDZQ8qvCS4ioCMibCwQg== dependencies: - "@sentry-internal/replay" "8.34.0" - "@sentry/core" "8.34.0" - "@sentry/types" "8.34.0" - "@sentry/utils" "8.34.0" + "@sentry-internal/replay" "8.35.0" + "@sentry/core" "8.35.0" + "@sentry/types" "8.35.0" + "@sentry/utils" "8.35.0" -"@sentry-internal/replay@8.34.0": - version "8.34.0" - resolved "https://registry.yarnpkg.com/@sentry-internal/replay/-/replay-8.34.0.tgz#b730919a174cc5ae8a77f79fb24a5ffb18e44db5" - integrity sha512-EoMh9NYljNewZK1quY23YILgtNdGgrkzJ9TPsj6jXUG0LZ0Q7N7eFWd0xOEDBvFxrmI3cSXF1i4d1sBb+eyKRw== +"@sentry-internal/replay@8.35.0": + version "8.35.0" + resolved "https://registry.yarnpkg.com/@sentry-internal/replay/-/replay-8.35.0.tgz#f71abae95cb492a54b43885386adbc5c639486c7" + integrity sha512-3wkW03vXYMyWtTLxl9yrtkV+qxbnKFgfASdoGWhXzfLjycgT6o4/04eb3Gn71q9aXqRwH17ISVQbVswnRqMcmA== dependencies: - "@sentry-internal/browser-utils" "8.34.0" - "@sentry/core" "8.34.0" - "@sentry/types" "8.34.0" - "@sentry/utils" "8.34.0" + "@sentry-internal/browser-utils" "8.35.0" + "@sentry/core" "8.35.0" + "@sentry/types" "8.35.0" + "@sentry/utils" "8.35.0" "@sentry/babel-plugin-component-annotate@2.22.5": version "2.22.5" @@ -2361,17 +2373,17 @@ integrity sha512-+93qwB9vTX1nj4hD8AMWowXZsZVkvmP9OwTqSh5d4kOeiJ+dZftUk4+FKeKkAX9lvY2reyHV8Gms5mo67c27RQ== "@sentry/browser@^8.0.0": - version "8.34.0" - resolved "https://registry.yarnpkg.com/@sentry/browser/-/browser-8.34.0.tgz#d2dfc2dbbfa9132d5c3e951f0a4b467805bc4c75" - integrity sha512-3HHG2NXxzHq1lVmDy2uRjYjGNf9NsJsTPlOC70vbQdOb+S49EdH/XMPy+J3ruIoyv6Cu0LwvA6bMOM6rHZOgNQ== + version "8.35.0" + resolved "https://registry.yarnpkg.com/@sentry/browser/-/browser-8.35.0.tgz#67820951fd092ef72ee1a4897464bc7c8d317d77" + integrity sha512-WHfI+NoZzpCsmIvtr6ChOe7yWPLQyMchPnVhY3Z4UeC70bkYNdKcoj/4XZbX3m0D8+71JAsm0mJ9s9OC3Ue6MQ== dependencies: - "@sentry-internal/browser-utils" "8.34.0" - "@sentry-internal/feedback" "8.34.0" - "@sentry-internal/replay" "8.34.0" - "@sentry-internal/replay-canvas" "8.34.0" - "@sentry/core" "8.34.0" - "@sentry/types" "8.34.0" - "@sentry/utils" "8.34.0" + "@sentry-internal/browser-utils" "8.35.0" + "@sentry-internal/feedback" "8.35.0" + "@sentry-internal/replay" "8.35.0" + "@sentry-internal/replay-canvas" "8.35.0" + "@sentry/core" "8.35.0" + "@sentry/types" "8.35.0" + "@sentry/utils" "8.35.0" "@sentry/bundler-plugin-core@2.22.5": version "2.22.5" @@ -2441,25 +2453,25 @@ "@sentry/cli-win32-i686" "2.37.0" "@sentry/cli-win32-x64" "2.37.0" -"@sentry/core@8.34.0": - version "8.34.0" - resolved "https://registry.yarnpkg.com/@sentry/core/-/core-8.34.0.tgz#92efe1cc8ced843beee636c344e66086d8915563" - integrity sha512-adrXCTK/zsg5pJ67lgtZqdqHvyx6etMjQW3P82NgWdj83c8fb+zH+K79Z47pD4zQjX0ou2Ws5nwwi4wJbz4bfA== +"@sentry/core@8.35.0": + version "8.35.0" + resolved "https://registry.yarnpkg.com/@sentry/core/-/core-8.35.0.tgz#17090f4d2d3bb983d9d99ecd2d27f4e9e107e0b0" + integrity sha512-Ci0Nmtw5ETWLqQJGY4dyF+iWh7PWKy6k303fCEoEmqj2czDrKJCp7yHBNV0XYbo00prj2ZTbCr6I7albYiyONA== dependencies: - "@sentry/types" "8.34.0" - "@sentry/utils" "8.34.0" + "@sentry/types" "8.35.0" + "@sentry/utils" "8.35.0" -"@sentry/types@8.34.0": - version "8.34.0" - resolved "https://registry.yarnpkg.com/@sentry/types/-/types-8.34.0.tgz#b02da72d1be67df5246aa9a97ca661ee71569372" - integrity sha512-zLRc60CzohGCo6zNsNeQ9JF3SiEeRE4aDCP9fDDdIVCOKovS+mn1rtSip0qd0Vp2fidOu0+2yY0ALCz1A3PJSQ== +"@sentry/types@8.35.0": + version "8.35.0" + resolved "https://registry.yarnpkg.com/@sentry/types/-/types-8.35.0.tgz#535c807800f7e378f61416f30177c0ef81b95012" + integrity sha512-AVEZjb16MlYPifiDDvJ19dPQyDn0jlrtC1PHs6ZKO+Rzyz+2EX2BRdszvanqArldexPoU1p5Bn2w81XZNXThBA== -"@sentry/utils@8.34.0": - version "8.34.0" - resolved "https://registry.yarnpkg.com/@sentry/utils/-/utils-8.34.0.tgz#5ba543381a9de0ada1196df1fc5cde3b891de41e" - integrity sha512-W1KoRlFUjprlh3t86DZPFxLfM6mzjRzshVfMY7vRlJFymBelJsnJ3A1lPeBZM9nCraOSiw6GtOWu6k5BAkiGIg== +"@sentry/utils@8.35.0": + version "8.35.0" + resolved "https://registry.yarnpkg.com/@sentry/utils/-/utils-8.35.0.tgz#1e099fcbc60040091c79f028a83226c145d588ee" + integrity sha512-MdMb6+uXjqND7qIPWhulubpSeHzia6HtxeJa8jYI09OCvIcmNGPydv/Gx/LZBwosfMHrLdTWcFH7Y7aCxrq7cg== dependencies: - "@sentry/types" "8.34.0" + "@sentry/types" "8.35.0" "@sentry/webpack-plugin@^2.7.1": version "2.22.5" @@ -2631,9 +2643,9 @@ pretty-format "^27.0.2" "@testing-library/jest-dom@^6.4.8": - version "6.6.1" - resolved "https://registry.yarnpkg.com/@testing-library/jest-dom/-/jest-dom-6.6.1.tgz#835612c9d8c529c835b15bbc1d1a924310c6c73c" - integrity sha512-mNYIiAuP4yJwV2zBRQCV7PHoQwbb6/8TfMpPcwSUzcSVDJHWOXt6hjNtIN1v5knDmimYnjJxKhsoVd4LVGIO+w== + version "6.6.2" + resolved "https://registry.yarnpkg.com/@testing-library/jest-dom/-/jest-dom-6.6.2.tgz#8186aa9a07263adef9cc5a59a4772db8c31f4a5b" + integrity sha512-P6GJD4yqc9jZLbe98j/EkyQDTPgqftohZF5FBkHY5BUERZmcf4HeO2k0XaefEg329ux2p21i1A1DmyQ1kKw2Jw== dependencies: "@adobe/css-tools" "^4.4.0" aria-query "^5.0.0" @@ -3078,10 +3090,10 @@ dependencies: "@types/react" "*" -"@types/react-dom@18.3.0": - version "18.3.0" - resolved "https://registry.yarnpkg.com/@types/react-dom/-/react-dom-18.3.0.tgz#0cbc818755d87066ab6ca74fbedb2547d74a82b0" - integrity sha512-EhwApuTmMBmXuFOikhQLIBUn6uFg81SwLMOAUgodJF14SOBOCMdU04gDoYi0WOJJHD144TL32z4yDqCW3dnkQg== +"@types/react-dom@18.3.1": + version "18.3.1" + resolved "https://registry.yarnpkg.com/@types/react-dom/-/react-dom-18.3.1.tgz#1e4654c08a9cdcfb6594c780ac59b55aad42fe07" + integrity sha512-qW1Mfv8taImTthu4KoXgDfLuk4bydU6Q/TkADnDWWHwi4NX4BR+LWfTp2sVmTqRrsHvyDDTelgelxJ+SsejKKQ== dependencies: "@types/react" "*" @@ -3218,29 +3230,29 @@ "@types/yargs-parser" "*" "@typescript-eslint/eslint-plugin@^8.0.0": - version "8.10.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.10.0.tgz#9c8218ed62f9a322df10ded7c34990f014df44f2" - integrity sha512-phuB3hoP7FFKbRXxjl+DRlQDuJqhpOnm5MmtROXyWi3uS/Xg2ZXqiQfcG2BJHiN4QKyzdOJi3NEn/qTnjUlkmQ== + version "8.12.2" + resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.12.2.tgz#c2ef660bb83fd1432368319312a2581fc92ccac1" + integrity sha512-gQxbxM8mcxBwaEmWdtLCIGLfixBMHhQjBqR8sVWNTPpcj45WlYL2IObS/DNMLH1DBP0n8qz+aiiLTGfopPEebw== dependencies: "@eslint-community/regexpp" "^4.10.0" - "@typescript-eslint/scope-manager" "8.10.0" - "@typescript-eslint/type-utils" "8.10.0" - "@typescript-eslint/utils" "8.10.0" - "@typescript-eslint/visitor-keys" "8.10.0" + "@typescript-eslint/scope-manager" "8.12.2" + "@typescript-eslint/type-utils" "8.12.2" + "@typescript-eslint/utils" "8.12.2" + "@typescript-eslint/visitor-keys" "8.12.2" graphemer "^1.4.0" ignore "^5.3.1" natural-compare "^1.4.0" ts-api-utils "^1.3.0" "@typescript-eslint/parser@^8.0.0": - version "8.10.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-8.10.0.tgz#3cbe7206f5e42835878a74a76da533549f977662" - integrity sha512-E24l90SxuJhytWJ0pTQydFT46Nk0Z+bsLKo/L8rtQSL93rQ6byd1V/QbDpHUTdLPOMsBCcYXZweADNCfOCmOAg== + version "8.12.2" + resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-8.12.2.tgz#2e8173b34e1685e918b2d571c16c906d3747bad2" + integrity sha512-MrvlXNfGPLH3Z+r7Tk+Z5moZAc0dzdVjTgUgwsdGweH7lydysQsnSww3nAmsq8blFuRD5VRlAr9YdEFw3e6PBw== dependencies: - "@typescript-eslint/scope-manager" "8.10.0" - "@typescript-eslint/types" "8.10.0" - "@typescript-eslint/typescript-estree" "8.10.0" - "@typescript-eslint/visitor-keys" "8.10.0" + "@typescript-eslint/scope-manager" "8.12.2" + "@typescript-eslint/types" "8.12.2" + "@typescript-eslint/typescript-estree" "8.12.2" + "@typescript-eslint/visitor-keys" "8.12.2" debug "^4.3.4" "@typescript-eslint/scope-manager@8.10.0": @@ -3251,6 +3263,14 @@ "@typescript-eslint/types" "8.10.0" "@typescript-eslint/visitor-keys" "8.10.0" +"@typescript-eslint/scope-manager@8.12.2": + version "8.12.2" + resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-8.12.2.tgz#6db0213745e6392c8e90fe9af5915e6da32eb94a" + integrity sha512-gPLpLtrj9aMHOvxJkSbDBmbRuYdtiEbnvO25bCMza3DhMjTQw0u7Y1M+YR5JPbMsXXnSPuCf5hfq0nEkQDL/JQ== + dependencies: + "@typescript-eslint/types" "8.12.2" + "@typescript-eslint/visitor-keys" "8.12.2" + "@typescript-eslint/scope-manager@8.9.0": version "8.9.0" resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-8.9.0.tgz#c98fef0c4a82a484e6a1eb610a55b154d14d46f3" @@ -3259,13 +3279,13 @@ "@typescript-eslint/types" "8.9.0" "@typescript-eslint/visitor-keys" "8.9.0" -"@typescript-eslint/type-utils@8.10.0": - version "8.10.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/type-utils/-/type-utils-8.10.0.tgz#99f1d2e21f8c74703e7d9c4a67a87271eaf57597" - integrity sha512-PCpUOpyQSpxBn230yIcK+LeCQaXuxrgCm2Zk1S+PTIRJsEfU6nJ0TtwyH8pIwPK/vJoA+7TZtzyAJSGBz+s/dg== +"@typescript-eslint/type-utils@8.12.2": + version "8.12.2" + resolved "https://registry.yarnpkg.com/@typescript-eslint/type-utils/-/type-utils-8.12.2.tgz#132b0c52d45f6814e6f2e32416c7951ed480b016" + integrity sha512-bwuU4TAogPI+1q/IJSKuD4shBLc/d2vGcRT588q+jzayQyjVK2X6v/fbR4InY2U2sgf8MEvVCqEWUzYzgBNcGQ== dependencies: - "@typescript-eslint/typescript-estree" "8.10.0" - "@typescript-eslint/utils" "8.10.0" + "@typescript-eslint/typescript-estree" "8.12.2" + "@typescript-eslint/utils" "8.12.2" debug "^4.3.4" ts-api-utils "^1.3.0" @@ -3274,6 +3294,11 @@ resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-8.10.0.tgz#eb29c4bc2ed23489348c297469c76d28c38fb618" integrity sha512-k/E48uzsfJCRRbGLapdZgrX52csmWJ2rcowwPvOZ8lwPUv3xW6CcFeJAXgx4uJm+Ge4+a4tFOkdYvSpxhRhg1w== +"@typescript-eslint/types@8.12.2": + version "8.12.2" + resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-8.12.2.tgz#8d70098c0e90442495b53d0296acdca6d0f3f73c" + integrity sha512-VwDwMF1SZ7wPBUZwmMdnDJ6sIFk4K4s+ALKLP6aIQsISkPv8jhiw65sAK6SuWODN/ix+m+HgbYDkH+zLjrzvOA== + "@typescript-eslint/types@8.9.0": version "8.9.0" resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-8.9.0.tgz#b733af07fb340b32e962c6c63b1062aec2dc0fe6" @@ -3293,6 +3318,20 @@ semver "^7.6.0" ts-api-utils "^1.3.0" +"@typescript-eslint/typescript-estree@8.12.2": + version "8.12.2" + resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-8.12.2.tgz#206df9b1cbff212aaa9401985ef99f04daa84da5" + integrity sha512-mME5MDwGe30Pq9zKPvyduyU86PH7aixwqYR2grTglAdB+AN8xXQ1vFGpYaUSJ5o5P/5znsSBeNcs5g5/2aQwow== + dependencies: + "@typescript-eslint/types" "8.12.2" + "@typescript-eslint/visitor-keys" "8.12.2" + debug "^4.3.4" + fast-glob "^3.3.2" + is-glob "^4.0.3" + minimatch "^9.0.4" + semver "^7.6.0" + ts-api-utils "^1.3.0" + "@typescript-eslint/typescript-estree@8.9.0": version "8.9.0" resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-8.9.0.tgz#1714f167e9063062dc0df49c1d25afcbc7a96199" @@ -3307,15 +3346,15 @@ semver "^7.6.0" ts-api-utils "^1.3.0" -"@typescript-eslint/utils@8.10.0", "@typescript-eslint/utils@^8.8.0": - version "8.10.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/utils/-/utils-8.10.0.tgz#d78d1ce3ea3d2a88a2593ebfb1c98490131d00bf" - integrity sha512-Oq4uZ7JFr9d1ZunE/QKy5egcDRXT/FrS2z/nlxzPua2VHFtmMvFNDvpq1m/hq0ra+T52aUezfcjGRIB7vNJF9w== +"@typescript-eslint/utils@8.12.2": + version "8.12.2" + resolved "https://registry.yarnpkg.com/@typescript-eslint/utils/-/utils-8.12.2.tgz#726cc9f49f5866605bd15bbc1768ffc15637930e" + integrity sha512-UTTuDIX3fkfAz6iSVa5rTuSfWIYZ6ATtEocQ/umkRSyC9O919lbZ8dcH7mysshrCdrAM03skJOEYaBugxN+M6A== dependencies: "@eslint-community/eslint-utils" "^4.4.0" - "@typescript-eslint/scope-manager" "8.10.0" - "@typescript-eslint/types" "8.10.0" - "@typescript-eslint/typescript-estree" "8.10.0" + "@typescript-eslint/scope-manager" "8.12.2" + "@typescript-eslint/types" "8.12.2" + "@typescript-eslint/typescript-estree" "8.12.2" "@typescript-eslint/utils@^6.0.0 || ^7.0.0 || ^8.0.0": version "8.9.0" @@ -3327,6 +3366,16 @@ "@typescript-eslint/types" "8.9.0" "@typescript-eslint/typescript-estree" "8.9.0" +"@typescript-eslint/utils@^8.8.0": + version "8.10.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/utils/-/utils-8.10.0.tgz#d78d1ce3ea3d2a88a2593ebfb1c98490131d00bf" + integrity sha512-Oq4uZ7JFr9d1ZunE/QKy5egcDRXT/FrS2z/nlxzPua2VHFtmMvFNDvpq1m/hq0ra+T52aUezfcjGRIB7vNJF9w== + dependencies: + "@eslint-community/eslint-utils" "^4.4.0" + "@typescript-eslint/scope-manager" "8.10.0" + "@typescript-eslint/types" "8.10.0" + "@typescript-eslint/typescript-estree" "8.10.0" + "@typescript-eslint/visitor-keys@8.10.0": version "8.10.0" resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-8.10.0.tgz#7ce4c0c3b82140415c9cd9babe09e0000b4e9979" @@ -3335,6 +3384,14 @@ "@typescript-eslint/types" "8.10.0" eslint-visitor-keys "^3.4.3" +"@typescript-eslint/visitor-keys@8.12.2": + version "8.12.2" + resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-8.12.2.tgz#94d7410f78eb6d134b9fcabaf1eeedb910ba8c38" + integrity sha512-PChz8UaKQAVNHghsHcPyx1OMHoFRUEA7rJSK/mDhdq85bk+PLsUHUBqTQTFt18VJZbmxBovM65fezlheQRsSDA== + dependencies: + "@typescript-eslint/types" "8.12.2" + eslint-visitor-keys "^3.4.3" + "@typescript-eslint/visitor-keys@8.9.0": version "8.9.0" resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-8.9.0.tgz#5f11f4d9db913f37da42776893ffe0dd1ae78f78" @@ -3349,9 +3406,9 @@ integrity sha512-zuVdFrMJiuCDQUMCzQaD6KL28MjnqqN8XnAqiEq9PNm/hCPTSGfrXCOfwj1ow4LFb/tNymJPwsNbVePc1xFqrQ== "@vector-im/compound-design-tokens@^1.8.0": - version "1.8.0" - resolved "https://registry.yarnpkg.com/@vector-im/compound-design-tokens/-/compound-design-tokens-1.8.0.tgz#bc844cb6b9842c1eb8e5c42f5cedcaf51a49b86f" - integrity sha512-PtQMG7kDzwtjw/fLKD63uWP5rJ8cgWc/aXarfEzxYUf9ceWxBajnYOBI2jDqtE3WIUe9uTVBzNEvmOBG/VIgTA== + version "1.9.0" + resolved "https://registry.yarnpkg.com/@vector-im/compound-design-tokens/-/compound-design-tokens-1.9.0.tgz#a3788845110fdcafb1720f633cb060b86f9a1592" + integrity sha512-09eIRJSiWtAqK605eIu+PfT1ugu7u13gkvfxvfN7kjJMHQOzHSvDxmwADmfIzlV7oBQ8M+5D4KSKHNskvMxWsA== "@vector-im/compound-web@^7.1.0": version "7.1.0" @@ -3884,10 +3941,10 @@ await-lock@^2.1.0: resolved "https://registry.yarnpkg.com/await-lock/-/await-lock-2.2.2.tgz#a95a9b269bfd2f69d22b17a321686f551152bcef" integrity sha512-aDczADvlvTGajTDjcjpJMqRkOF6Qdz3YbPZm/PyW6tKPkx2hlYBzxMhEywM/tU72HrVZjgl5VCdRuMlA7pZ8Gw== -axe-core@4.10.0: - version "4.10.0" - resolved "https://registry.yarnpkg.com/axe-core/-/axe-core-4.10.0.tgz#d9e56ab0147278272739a000880196cdfe113b59" - integrity sha512-Mr2ZakwQ7XUAjp7pAwQWRhhK8mQQ6JAaNWSjmjxil0R8BPioMtQsTLOolGYkji1rcL++3dCqZA3zWqpT+9Ew6g== +axe-core@4.10.2: + version "4.10.2" + resolved "https://registry.yarnpkg.com/axe-core/-/axe-core-4.10.2.tgz#85228e3e1d8b8532a27659b332e39b7fa0e022df" + integrity sha512-RE3mdQ7P3FRSe7eqCWoeQ/Z9QXrtniSjp1wUjt5nRC3WIpz5rSCve6o3fsZ2aCpJtrZjSZgjwXAoTO5k4tEI0w== axe-core@^4.10.0, axe-core@~4.10.0: version "4.10.1" @@ -5626,10 +5683,10 @@ eslint-plugin-matrix-org@^2.0.2: resolved "https://registry.yarnpkg.com/eslint-plugin-matrix-org/-/eslint-plugin-matrix-org-2.0.2.tgz#95b86b0f16704ab19740f7c3c62eae69e20365e6" integrity sha512-cQy5Rjeq6uyu1mLXlPZwEJdyM0NmclrnEz68y792FSuuxzMyJNNYLGDQ5CkYW8H+PrD825HUFZ34pNXnjMOzOw== -eslint-plugin-react-hooks@^4.3.0: - version "4.6.2" - resolved "https://registry.yarnpkg.com/eslint-plugin-react-hooks/-/eslint-plugin-react-hooks-4.6.2.tgz#c829eb06c0e6f484b3fbb85a97e57784f328c596" - integrity sha512-QzliNJq4GinDBcD8gPB5v0wh6g8q3SUi6EFF0x8N/BL9PoVs0atuGc47ozMRyOWAKdwaZ5OnbOEa3WR+dSGKuQ== +eslint-plugin-react-hooks@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/eslint-plugin-react-hooks/-/eslint-plugin-react-hooks-5.0.0.tgz#72e2eefbac4b694f5324154619fee44f5f60f101" + integrity sha512-hIOwI+5hYGpJEc4uPRmz2ulCjAGD/N13Lukkh8cLV0i2IRk/bdZDYjgLVHj+U9Z704kLIdIO6iueGvxNur0sgw== eslint-plugin-react@^7.28.0: version "7.37.1" @@ -8320,10 +8377,10 @@ mdn-data@2.10.0: resolved "https://registry.yarnpkg.com/mdn-data/-/mdn-data-2.10.0.tgz#701da407f8fbc7a42aa0ba0c149ec897daef8986" integrity sha512-qq7C3EtK3yJXMwz1zAab65pjl+UhohqMOctTgcqjLOWABqmwj+me02LSsCuEUxnst9X1lCBpoE0WArGKgdGDzw== -mdn-data@^2.0.30: - version "2.11.1" - resolved "https://registry.yarnpkg.com/mdn-data/-/mdn-data-2.11.1.tgz#bb973c4272a446005444259fd8227d7f727dc047" - integrity sha512-Hdx3wmyqPFrhd6YHVuSkUK2eIGAcxR0xlndcgZqjA68yMJTbfXrjJwbgsBOsNjI7LnBIVUQnmyMVSdi/ob0GpQ== +mdn-data@^2.11.1: + version "2.12.1" + resolved "https://registry.yarnpkg.com/mdn-data/-/mdn-data-2.12.1.tgz#10cb462215c13d95c92ff60d0fb3becac1bbb924" + integrity sha512-rsfnCbOHjqrhWxwt5/wtSLzpoKTzW7OXdT5lLOIH1OTYhWu9rRJveGq0sKvDZODABH7RX+uoR+DYcpFnq4Tf6Q== mdurl@^1.0.1, mdurl@~1.0.1: version "1.0.1" @@ -9088,17 +9145,17 @@ pkg-dir@^7.0.0: dependencies: find-up "^6.3.0" -playwright-core@1.48.1, playwright-core@^1.45.1: - version "1.48.1" - resolved "https://registry.yarnpkg.com/playwright-core/-/playwright-core-1.48.1.tgz#5fe28fb9a9326dae88d4608c35e819163cceeb23" - integrity sha512-Yw/t4VAFX/bBr1OzwCuOMZkY1Cnb4z/doAFSwf4huqAGWmf9eMNjmK7NiOljCdLmxeRYcGPPmcDgU0zOlzP0YA== +playwright-core@1.48.2, playwright-core@^1.45.1: + version "1.48.2" + resolved "https://registry.yarnpkg.com/playwright-core/-/playwright-core-1.48.2.tgz#cd76ed8af61690edef5c05c64721c26a8db2f3d7" + integrity sha512-sjjw+qrLFlriJo64du+EK0kJgZzoQPsabGF4lBvsid+3CNIZIYLgnMj9V6JY5VhM2Peh20DJWIVpVljLLnlawA== -playwright@1.48.1: - version "1.48.1" - resolved "https://registry.yarnpkg.com/playwright/-/playwright-1.48.1.tgz#2a920cfbec4572c84789e757d8b044baaed49435" - integrity sha512-j8CiHW/V6HxmbntOfyB4+T/uk08tBy6ph0MpBXwuoofkSnLmlfdYNNkFTYD6ofzzlSqLA1fwH4vwvVFvJgLN0w== +playwright@1.48.2: + version "1.48.2" + resolved "https://registry.yarnpkg.com/playwright/-/playwright-1.48.2.tgz#fca45ae8abdc34835c715718072aaff7e305167e" + integrity sha512-NjYvYgp4BPmiwfe31j4gHLa3J7bD2WiBz8Lk2RoSsmX38SVIARZ18VYjxLjAcDsAhA+F4iSEXTSGgjua0rrlgQ== dependencies: - playwright-core "1.48.1" + playwright-core "1.48.2" optionalDependencies: fsevents "2.3.2" @@ -11019,14 +11076,14 @@ stylelint-config-standard@^36.0.0: stylelint-config-recommended "^14.0.1" stylelint-scss@^6.0.0: - version "6.8.0" - resolved "https://registry.yarnpkg.com/stylelint-scss/-/stylelint-scss-6.8.0.tgz#bf3992bdb708b78b115a039f5be97dd7482133fa" - integrity sha512-6gjsCZ30UUF6ivjZB2Z+1lb6k0+JFa1uR2MgGbYu76xRjEfvNTpSS1nQim1Gom1ijFF9GzauOiq1Kr7zKptQOw== + version "6.8.1" + resolved "https://registry.yarnpkg.com/stylelint-scss/-/stylelint-scss-6.8.1.tgz#b6554d93f2ea0bf37ffdcae571bbfaa35d79ba8a" + integrity sha512-al+5eRb72bKrFyVAY+CLWKUMX+k+wsDCgyooSfhISJA2exqnJq1PX1iIIpdrvhu3GtJgNJZl9/BIW6EVSMCxdg== dependencies: css-tree "^3.0.0" is-plain-object "^5.0.0" known-css-properties "^0.34.0" - mdn-data "^2.0.30" + mdn-data "^2.11.1" postcss-media-query-parser "^0.2.3" postcss-resolve-nested-selector "^0.1.6" postcss-selector-parser "^6.1.2" @@ -11388,7 +11445,7 @@ tsconfig-paths@^3.15.0: minimist "^1.2.6" strip-bom "^3.0.0" -tslib@^2.0.0, tslib@^2.0.3, tslib@^2.1.0, tslib@^2.4.0, tslib@^2.6.1, tslib@^2.6.2, tslib@^2.7.0: +tslib@2, tslib@^2.0.0, tslib@^2.0.3, tslib@^2.1.0, tslib@^2.4.0, tslib@^2.6.1, tslib@^2.6.2, tslib@^2.7.0: version "2.8.0" resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.8.0.tgz#d124c86c3c05a40a91e6fdea4021bd31d377971b" integrity sha512-jWVzBLplnCmoaTr13V9dYbiQ99wvZRd0vNWaDRg+aVYRcjDF3nDksxFDE/+fkXnKhpnUUkmx5pK/v8mCtLVqZA== @@ -11644,7 +11701,7 @@ utils-merge@1.0.1: resolved "https://registry.yarnpkg.com/utils-merge/-/utils-merge-1.0.1.tgz#9f95710f50a267947b2ccc124741c1028427e713" integrity sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA== -uuid@10, uuid@^10.0.0: +uuid@10: version "10.0.0" resolved "https://registry.yarnpkg.com/uuid/-/uuid-10.0.0.tgz#5a95aa454e6e002725c79055fd42aaba30ca6294" integrity sha512-8XkAphELsDnEGrDxUOHB3RGvXz6TeuYSGEZBOjtTtPm2lwhGBjLgOzLHB63IUWfBpNucQjND6d3AOudO+H3RWQ== @@ -11654,6 +11711,11 @@ uuid@8.3.2, uuid@^8.3.2: resolved "https://registry.yarnpkg.com/uuid/-/uuid-8.3.2.tgz#80d5b5ced271bb9af6c445f21a1a04c606cefbe2" integrity sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg== +uuid@^11.0.0: + version "11.0.2" + resolved "https://registry.yarnpkg.com/uuid/-/uuid-11.0.2.tgz#a8d68ba7347d051e7ea716cc8dcbbab634d66875" + integrity sha512-14FfcOJmqdjbBPdDjFQyk/SdT4NySW4eM0zcG+HqbHP5jzuH56xO3J1DGhgs/cEMCfwYi3HQI1gnTO62iaG+tQ== + uuid@^9.0.0: version "9.0.1" resolved "https://registry.yarnpkg.com/uuid/-/uuid-9.0.1.tgz#e188d4c8853cc722220392c424cd637f32293f30"