From 0bbed853daec9acdfb4b95fa78c0796f614d3124 Mon Sep 17 00:00:00 2001 From: David Baker <dbkr@users.noreply.github.com> Date: Wed, 18 Sep 2024 16:36:30 +0100 Subject: [PATCH 01/21] Pass bot token through explicitly (#56) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Because apparently secrets: inherit only works for environment secrets, and it only took me several hours of research to track this down 🙄 --- .github/workflows/release.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index eddca83555..237a549738 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -19,7 +19,8 @@ concurrency: ${{ github.workflow }} jobs: release: uses: matrix-org/matrix-js-sdk/.github/workflows/release-make.yml@develop - secrets: inherit + secrets: + ELEMENT_BOT_TOKEN: ${{ secrets.ELEMENT_BOT_TOKEN }} with: final: ${{ inputs.mode == 'final' }} npm: ${{ inputs.npm }} From 154bf33fa1284c83c4abb52e9cdaab726515e603 Mon Sep 17 00:00:00 2001 From: David Langley <davidl@element.io> Date: Wed, 18 Sep 2024 17:56:18 +0100 Subject: [PATCH 02/21] Manually clear orphaned recaptcha challenge overlay in android webviews (#53) * try manually clear any left over recaptcha overalys * add alert to debug webview * disable settings check for netlify build * Update fix for removing challenge, as g-recaptcha-bubble-arrow is now always shown * Remove alert for debugging webview * Put back requirement for config setting and make sure it redirects to welcome if not present. * Add comment to explain bodge. * Remove unrelated code --- src/components/views/auth/CaptchaForm.tsx | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/src/components/views/auth/CaptchaForm.tsx b/src/components/views/auth/CaptchaForm.tsx index 2b82f4cea0..f216f004fd 100644 --- a/src/components/views/auth/CaptchaForm.tsx +++ b/src/components/views/auth/CaptchaForm.tsx @@ -63,6 +63,19 @@ export default class CaptchaForm extends React.Component<ICaptchaFormProps, ICap public componentWillUnmount(): void { this.resetRecaptcha(); + // Resettting the captcha does not clear the challenge overlay from the body in android webviews. + // Search for an iframe with the challenge src and remove it's topmost ancestor from the body. + // TODO: Remove this when the "mobile_register" page is retired. + const iframes = document.querySelectorAll("iframe"); + for (const iframe of iframes) { + if (iframe.src.includes("https://www.recaptcha.net/recaptcha/api2/bframe")) { + let parentBeforeBody: HTMLElement | null = iframe; + do { + parentBeforeBody = parentBeforeBody.parentElement; + } while (parentBeforeBody?.parentElement && parentBeforeBody.parentElement != document.body); + parentBeforeBody?.remove(); + } + } } // Borrowed directly from: https://github.com/codeep/react-recaptcha-google/commit/e118fa5670fa268426969323b2e7fe77698376ba From 1e7631386e15bace6d5e3944ab541fae7bba40c5 Mon Sep 17 00:00:00 2001 From: Richard van der Hoff <1389908+richvdh@users.noreply.github.com> Date: Thu, 19 Sep 2024 08:13:04 +0100 Subject: [PATCH 03/21] Playwright: factor out some common code (#49) * playwright: factor out `bootstrapCrossSigningForClient` method Pull this out so it can be used elsewhere. Also expose the `resetKeys` param, which might be useful in future. * playwright: bot.ts: use `bootstrapCrossSigningForClient` ... instead of reinventing it. * Only setup cross signing if `startClient` is set --- playwright/pages/bot.ts | 89 +++++++++++++++++++------------------- playwright/pages/client.ts | 45 ++++++++++++------- 2 files changed, 75 insertions(+), 59 deletions(-) diff --git a/playwright/pages/bot.ts b/playwright/pages/bot.ts index b7542338b6..d50a0e84ee 100644 --- a/playwright/pages/bot.ts +++ b/playwright/pages/bot.ts @@ -14,7 +14,7 @@ import type { Logger } from "matrix-js-sdk/src/logger"; import type { SecretStorageKeyDescription } from "matrix-js-sdk/src/secret-storage"; import type { Credentials, HomeserverInstance } from "../plugins/homeserver"; import type { GeneratedSecretStorageKey } from "matrix-js-sdk/src/crypto-api"; -import { Client } from "./client"; +import { bootstrapCrossSigningForClient, Client } from "./client"; export interface CreateBotOpts { /** @@ -90,9 +90,13 @@ export class Bot extends Client { } protected async getClientHandle(): Promise<JSHandle<ExtendedMatrixClient>> { - if (this.handlePromise) return this.handlePromise; + if (!this.handlePromise) this.handlePromise = this.buildClient(); + return this.handlePromise; + } - this.handlePromise = this.page.evaluateHandle( + private async buildClient(): Promise<JSHandle<ExtendedMatrixClient>> { + const credentials = await this.getCredentials(); + const clientHandle = await this.page.evaluateHandle( async ({ homeserver, credentials, opts }) => { function getLogger(loggerName: string): Logger { const logger = { @@ -172,53 +176,50 @@ export class Bot extends Client { }); } - if (!opts.startClient) { - return cli; - } - - await cli.initRustCrypto({ useIndexedDB: false }); - cli.setGlobalErrorOnUnknownDevices(false); - await cli.startClient(); - - if (opts.bootstrapCrossSigning) { - // XXX: workaround https://github.com/element-hq/element-web/issues/26755 - // wait for out device list to be available, as a proxy for the device keys having been uploaded. - await cli.getCrypto()!.getUserDeviceInfo([credentials.userId]); - - await cli.getCrypto()!.bootstrapCrossSigning({ - authUploadDeviceSigningKeys: async (func) => { - await func({ - type: "m.login.password", - identifier: { - type: "m.id.user", - user: credentials.userId, - }, - password: credentials.password, - }); - }, - }); - } - - if (opts.bootstrapSecretStorage) { - const passphrase = "new passphrase"; - const recoveryKey = await cli.getCrypto().createRecoveryKeyFromPassphrase(passphrase); - Object.assign(cli, { __playwright_recovery_key: recoveryKey }); - - await cli.getCrypto()!.bootstrapSecretStorage({ - setupNewSecretStorage: true, - setupNewKeyBackup: true, - createSecretStorageKey: () => Promise.resolve(recoveryKey), - }); - } - return cli; }, { homeserver: this.homeserver.config, - credentials: await this.getCredentials(), + credentials, opts: this.opts, }, ); - return this.handlePromise; + + // If we weren't configured to start the client, bail out now. + if (!this.opts.startClient) { + return clientHandle; + } + + await clientHandle.evaluate(async (cli) => { + await cli.initRustCrypto({ useIndexedDB: false }); + cli.setGlobalErrorOnUnknownDevices(false); + await cli.startClient(); + }); + + if (this.opts.bootstrapCrossSigning) { + // XXX: workaround https://github.com/element-hq/element-web/issues/26755 + // wait for out device list to be available, as a proxy for the device keys having been uploaded. + await clientHandle.evaluate(async (cli, credentials) => { + await cli.getCrypto()!.getUserDeviceInfo([credentials.userId]); + }, credentials); + + await bootstrapCrossSigningForClient(clientHandle, credentials); + } + + if (this.opts.bootstrapSecretStorage) { + await clientHandle.evaluate(async (cli) => { + const passphrase = "new passphrase"; + const recoveryKey = await cli.getCrypto().createRecoveryKeyFromPassphrase(passphrase); + Object.assign(cli, { __playwright_recovery_key: recoveryKey }); + + await cli.getCrypto()!.bootstrapSecretStorage({ + setupNewSecretStorage: true, + setupNewKeyBackup: true, + createSecretStorageKey: () => Promise.resolve(recoveryKey), + }); + }); + } + + return clientHandle; } } diff --git a/playwright/pages/client.ts b/playwright/pages/client.ts index 002a3340b2..06e05fdcfa 100644 --- a/playwright/pages/client.ts +++ b/playwright/pages/client.ts @@ -356,24 +356,11 @@ export class Client { } /** - * Boostraps cross-signing. + * Bootstraps cross-signing. */ public async bootstrapCrossSigning(credentials: Credentials): Promise<void> { const client = await this.prepareClient(); - return client.evaluate(async (client, credentials) => { - await client.getCrypto().bootstrapCrossSigning({ - authUploadDeviceSigningKeys: async (func) => { - await func({ - type: "m.login.password", - identifier: { - type: "m.id.user", - user: credentials.userId, - }, - password: credentials.password, - }); - }, - }); - }, credentials); + return bootstrapCrossSigningForClient(client, credentials); } /** @@ -439,3 +426,31 @@ export class Client { ); } } + +/** Call `CryptoApi.bootstrapCrossSigning` on the given Matrix client, using the given credentials to authenticate + * the UIA request. + */ +export function bootstrapCrossSigningForClient( + client: JSHandle<MatrixClient>, + credentials: Credentials, + resetKeys: boolean = false, +) { + return client.evaluate( + async (client, { credentials, resetKeys }) => { + await client.getCrypto().bootstrapCrossSigning({ + authUploadDeviceSigningKeys: async (func) => { + await func({ + type: "m.login.password", + identifier: { + type: "m.id.user", + user: credentials.userId, + }, + password: credentials.password, + }); + }, + setupNewCrossSigning: resetKeys, + }); + }, + { credentials, resetKeys }, + ); +} From 3dd223c7dde423ab5eeee2c773411c0172977cfc Mon Sep 17 00:00:00 2001 From: David Baker <dbkr@users.noreply.github.com> Date: Thu, 19 Sep 2024 09:37:25 +0100 Subject: [PATCH 04/21] Also add NPM_TOKEN (#57) --- .github/workflows/release.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 237a549738..9d1cb6e2d2 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -21,6 +21,7 @@ jobs: uses: matrix-org/matrix-js-sdk/.github/workflows/release-make.yml@develop secrets: ELEMENT_BOT_TOKEN: ${{ secrets.ELEMENT_BOT_TOKEN }} + NPM_TOKEN: ${{ secrets.NPM_TOKEN }} with: final: ${{ inputs.mode == 'final' }} npm: ${{ inputs.npm }} From 0cc0ebe2edeb5491a725b2f97d125eaff1b17792 Mon Sep 17 00:00:00 2001 From: Florian Duros <florian.duros@ormaz.fr> Date: Thu, 19 Sep 2024 11:34:04 +0200 Subject: [PATCH 05/21] Replace old reference of `matrix-org/matrix-react-sdk` by `element-hq/matrix-react-sdk` (#60) --- .github/workflows/notify-element-web.yml | 2 +- .github/workflows/tests.yml | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/notify-element-web.yml b/.github/workflows/notify-element-web.yml index 522a089edb..442a2f1082 100644 --- a/.github/workflows/notify-element-web.yml +++ b/.github/workflows/notify-element-web.yml @@ -9,7 +9,7 @@ jobs: name: "Notify Element Web" runs-on: ubuntu-latest # Only respect triggers from our develop branch, ignore that of forks - if: github.repository == 'matrix-org/matrix-react-sdk' + if: github.repository == 'element-hq/matrix-react-sdk' steps: - name: Notify element-web repo that a new SDK build is on develop uses: peter-evans/repository-dispatch@ff45666b9427631e3450c54a1bcbee4d9ff4d7c0 # v3 diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index e8418a9519..e306b32959 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -39,7 +39,7 @@ jobs: - name: Checkout code uses: actions/checkout@v4 with: - repository: ${{ inputs.matrix-js-sdk-sha && 'matrix-org/matrix-react-sdk' || github.repository }} + repository: ${{ inputs.matrix-js-sdk-sha && 'element-hq/matrix-react-sdk' || github.repository }} - name: Yarn cache uses: actions/setup-node@v4 @@ -111,7 +111,7 @@ jobs: steps: - uses: actions/checkout@v4 with: - repository: ${{ inputs.matrix-js-sdk-sha && 'matrix-org/matrix-react-sdk' || github.repository }} + repository: ${{ inputs.matrix-js-sdk-sha && 'element-hq/matrix-react-sdk' || github.repository }} - uses: actions/setup-node@v4 with: From 4776f87775f936a4b1319ee6b04b486fcf1133ef Mon Sep 17 00:00:00 2001 From: Florian Duros <florian.duros@ormaz.fr> Date: Thu, 19 Sep 2024 11:39:32 +0200 Subject: [PATCH 06/21] Ignore chat effect when older than 48h (#48) * Ignore effect later than 48h * Add tests for `EffectsOverlay-test.tsx` --- src/components/structures/RoomView.tsx | 2 +- .../views/elements/EffectsOverlay.tsx | 22 +++++++- .../views/elements/EffectsOverlay-test.tsx | 51 +++++++++++++++++++ .../EffectsOverlay-test.tsx.snap | 12 +++++ 4 files changed, 84 insertions(+), 3 deletions(-) create mode 100644 test/components/views/elements/EffectsOverlay-test.tsx create mode 100644 test/components/views/elements/__snapshots__/EffectsOverlay-test.tsx.snap diff --git a/src/components/structures/RoomView.tsx b/src/components/structures/RoomView.tsx index a65743a3e2..87e8c3c307 100644 --- a/src/components/structures/RoomView.tsx +++ b/src/components/structures/RoomView.tsx @@ -1364,7 +1364,7 @@ export class RoomView extends React.Component<IRoomProps, IRoomState> { if (containsEmoji(ev.getContent(), effect.emojis) || ev.getContent().msgtype === effect.msgType) { // For initial threads launch, chat effects are disabled see #19731 if (!ev.isRelation(THREAD_RELATION_TYPE.name)) { - dis.dispatch({ action: `effects.${effect.command}` }); + dis.dispatch({ action: `effects.${effect.command}`, event: ev }); } } }); diff --git a/src/components/views/elements/EffectsOverlay.tsx b/src/components/views/elements/EffectsOverlay.tsx index 76262ad4f0..3e5a5ead60 100644 --- a/src/components/views/elements/EffectsOverlay.tsx +++ b/src/components/views/elements/EffectsOverlay.tsx @@ -8,6 +8,7 @@ Please see LICENSE files in the repository root for full details. */ import React, { FunctionComponent, useEffect, useRef } from "react"; import { logger } from "matrix-js-sdk/src/logger"; +import { MatrixEvent } from "matrix-js-sdk/src/matrix"; import dis from "../../../dispatcher/dispatcher"; import ICanvasEffect from "../../../effects/ICanvasEffect"; @@ -44,9 +45,10 @@ const EffectsOverlay: FunctionComponent<IProps> = ({ roomWidth }) => { canvasRef.current.height = UIStore.instance.windowHeight; } }; - const onAction = (payload: { action: string }): void => { + const onAction = (payload: { action: string; event?: MatrixEvent }): void => { const actionPrefix = "effects."; - if (canvasRef.current && payload.action.startsWith(actionPrefix)) { + const isOutdated = isEventOutdated(payload.event); + if (canvasRef.current && payload.action.startsWith(actionPrefix) && !isOutdated) { const effect = payload.action.slice(actionPrefix.length); lazyLoadEffectModule(effect).then((module) => module?.start(canvasRef.current!)); } @@ -88,3 +90,19 @@ const EffectsOverlay: FunctionComponent<IProps> = ({ roomWidth }) => { }; export default EffectsOverlay; + +// 48 hours +// 48h * 60m * 60s * 1000ms +const OUTDATED_EVENT_THRESHOLD = 48 * 60 * 60 * 1000; + +/** + * Return true if the event is older than 48h. + * @param event + */ +function isEventOutdated(event?: MatrixEvent): boolean { + if (!event) return false; + + const nowTs = Date.now(); + const eventTs = event.getTs(); + return nowTs - eventTs > OUTDATED_EVENT_THRESHOLD; +} diff --git a/test/components/views/elements/EffectsOverlay-test.tsx b/test/components/views/elements/EffectsOverlay-test.tsx new file mode 100644 index 0000000000..48e508181d --- /dev/null +++ b/test/components/views/elements/EffectsOverlay-test.tsx @@ -0,0 +1,51 @@ +/* + * Copyright 2024 New Vector Ltd. + * + * 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 { render, waitFor } from "@testing-library/react"; + +import dis from "../../../../src/dispatcher/dispatcher"; +import EffectsOverlay from "../../../../src/components/views/elements/EffectsOverlay.tsx"; + +describe("<EffectsOverlay/>", () => { + let isStarted: boolean; + beforeEach(() => { + isStarted = false; + jest.mock("../../../../src/effects/confetti/index.ts", () => { + return class Confetti { + start = () => { + isStarted = true; + }; + stop = jest.fn(); + }; + }); + }); + + afterEach(() => jest.useRealTimers()); + + it("should render", () => { + const { asFragment } = render(<EffectsOverlay roomWidth={100} />); + expect(asFragment()).toMatchSnapshot(); + }); + + it("should start the confetti effect", async () => { + render(<EffectsOverlay roomWidth={100} />); + dis.dispatch({ action: "effects.confetti" }); + await waitFor(() => expect(isStarted).toBe(true)); + }); + + it("should start the confetti effect when the event is not outdated", async () => { + const eventDate = new Date("2024-09-01"); + const date = new Date("2024-09-02"); + jest.useFakeTimers().setSystemTime(date); + + render(<EffectsOverlay roomWidth={100} />); + dis.dispatch({ action: "effects.confetti", event: { getTs: () => eventDate.getTime() } }); + await waitFor(() => expect(isStarted).toBe(true)); + }); +}); diff --git a/test/components/views/elements/__snapshots__/EffectsOverlay-test.tsx.snap b/test/components/views/elements/__snapshots__/EffectsOverlay-test.tsx.snap new file mode 100644 index 0000000000..222d893e99 --- /dev/null +++ b/test/components/views/elements/__snapshots__/EffectsOverlay-test.tsx.snap @@ -0,0 +1,12 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`<EffectsOverlay/> should render 1`] = ` +<DocumentFragment> + <canvas + aria-hidden="true" + height="768" + style="display: block; z-index: 999999; pointer-events: none; position: fixed; top: 0px; right: 0px;" + width="100" + /> +</DocumentFragment> +`; From 490746e56aab4227f64895f43de24d2b189c0ffe Mon Sep 17 00:00:00 2001 From: Florian Duros <florian.duros@ormaz.fr> Date: Thu, 19 Sep 2024 15:41:11 +0200 Subject: [PATCH 07/21] Update to use non deprecated methods to derive key from passphrase (#55) * Replace `deriveKey` call by `deriveRecoveryKeyFromPassphrase` * Remove `matrix-js-sdk/src/crypto/key_passphrase` import of eslint exception --- .eslintrc.js | 1 - src/SecurityManager.ts | 4 ++-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/.eslintrc.js b/.eslintrc.js index 444388d492..9cb3e29fb7 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -122,7 +122,6 @@ module.exports = { "!matrix-js-sdk/src/crypto/aes", "!matrix-js-sdk/src/crypto/keybackup", "!matrix-js-sdk/src/crypto/deviceinfo", - "!matrix-js-sdk/src/crypto/key_passphrase", "!matrix-js-sdk/src/crypto/recoverykey", "!matrix-js-sdk/src/crypto/dehydration", "!matrix-js-sdk/src/oidc", diff --git a/src/SecurityManager.ts b/src/SecurityManager.ts index 6bfd361140..f03f83d573 100644 --- a/src/SecurityManager.ts +++ b/src/SecurityManager.ts @@ -7,7 +7,7 @@ Please see LICENSE files in the repository root for full details. */ import { ICryptoCallbacks, SecretStorage } from "matrix-js-sdk/src/matrix"; -import { deriveKey } from "matrix-js-sdk/src/crypto/key_passphrase"; +import { deriveRecoveryKeyFromPassphrase } from "matrix-js-sdk/src/crypto-api"; import { decodeRecoveryKey } from "matrix-js-sdk/src/crypto/recoverykey"; import { logger } from "matrix-js-sdk/src/logger"; @@ -64,7 +64,7 @@ function makeInputToKey( ): (keyParams: KeyParams) => Promise<Uint8Array> { return async ({ passphrase, recoveryKey }): Promise<Uint8Array> => { if (passphrase) { - return deriveKey(passphrase, keyInfo.passphrase.salt, keyInfo.passphrase.iterations); + return deriveRecoveryKeyFromPassphrase(passphrase, keyInfo.passphrase.salt, keyInfo.passphrase.iterations); } else if (recoveryKey) { return decodeRecoveryKey(recoveryKey); } From fe657027bdaf54c3d7e62aee8a0fe50fce53dee5 Mon Sep 17 00:00:00 2001 From: Florian Duros <florian.duros@ormaz.fr> Date: Thu, 19 Sep 2024 17:39:20 +0200 Subject: [PATCH 08/21] Update to use non deprecated methods to decode recovery key (#54) * Replace `MatrixClient.keyBackupKeyFromRecoveryKey` by `decodeRecoveryKey` * Replace `MatrixClient.isValidRecoveryKey` by local check with `decodeRecoveryKey` * Replace old `decodeRecoveryKey` import * Remove `matrix-js-sdk/src/crypto/recoverykey` import of eslint exception * Add tests for `RestoreKeyBackupDialog` --- .eslintrc.js | 1 - src/SecurityManager.ts | 3 +- .../security/AccessSecretStorageDialog.tsx | 3 +- .../security/RestoreKeyBackupDialog.tsx | 20 +- .../AccessSecretStorageDialog-test.tsx | 8 +- .../security/RestoreKeyBackupDialog-test.tsx | 51 +++ .../RestoreKeyBackupDialog-test.tsx.snap | 298 ++++++++++++++++++ 7 files changed, 371 insertions(+), 13 deletions(-) create mode 100644 test/components/views/dialogs/security/RestoreKeyBackupDialog-test.tsx create mode 100644 test/components/views/dialogs/security/__snapshots__/RestoreKeyBackupDialog-test.tsx.snap diff --git a/.eslintrc.js b/.eslintrc.js index 9cb3e29fb7..a3c7eb4f8d 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -122,7 +122,6 @@ module.exports = { "!matrix-js-sdk/src/crypto/aes", "!matrix-js-sdk/src/crypto/keybackup", "!matrix-js-sdk/src/crypto/deviceinfo", - "!matrix-js-sdk/src/crypto/recoverykey", "!matrix-js-sdk/src/crypto/dehydration", "!matrix-js-sdk/src/oidc", "!matrix-js-sdk/src/oidc/discovery", diff --git a/src/SecurityManager.ts b/src/SecurityManager.ts index f03f83d573..fb73e25389 100644 --- a/src/SecurityManager.ts +++ b/src/SecurityManager.ts @@ -7,8 +7,7 @@ Please see LICENSE files in the repository root for full details. */ import { ICryptoCallbacks, SecretStorage } from "matrix-js-sdk/src/matrix"; -import { deriveRecoveryKeyFromPassphrase } from "matrix-js-sdk/src/crypto-api"; -import { decodeRecoveryKey } from "matrix-js-sdk/src/crypto/recoverykey"; +import { deriveRecoveryKeyFromPassphrase, decodeRecoveryKey } from "matrix-js-sdk/src/crypto-api"; import { logger } from "matrix-js-sdk/src/logger"; import type CreateSecretStorageDialog from "./async-components/views/dialogs/security/CreateSecretStorageDialog"; diff --git a/src/components/views/dialogs/security/AccessSecretStorageDialog.tsx b/src/components/views/dialogs/security/AccessSecretStorageDialog.tsx index 3759e11063..0c4e875607 100644 --- a/src/components/views/dialogs/security/AccessSecretStorageDialog.tsx +++ b/src/components/views/dialogs/security/AccessSecretStorageDialog.tsx @@ -10,6 +10,7 @@ import { debounce } from "lodash"; import classNames from "classnames"; import React, { ChangeEvent, FormEvent } from "react"; import { logger } from "matrix-js-sdk/src/logger"; +import { decodeRecoveryKey } from "matrix-js-sdk/src/crypto-api"; import { SecretStorage } from "matrix-js-sdk/src/matrix"; import { MatrixClientPeg } from "../../../../MatrixClientPeg"; @@ -100,7 +101,7 @@ export default class AccessSecretStorageDialog extends React.PureComponent<IProp try { const cli = MatrixClientPeg.safeGet(); - const decodedKey = cli.keyBackupKeyFromRecoveryKey(this.state.recoveryKey); + const decodedKey = decodeRecoveryKey(this.state.recoveryKey); const correct = await cli.checkSecretStorageKey(decodedKey, this.props.keyInfo); this.setState({ recoveryKeyValid: true, diff --git a/src/components/views/dialogs/security/RestoreKeyBackupDialog.tsx b/src/components/views/dialogs/security/RestoreKeyBackupDialog.tsx index 73ec69a1fc..c5963b966c 100644 --- a/src/components/views/dialogs/security/RestoreKeyBackupDialog.tsx +++ b/src/components/views/dialogs/security/RestoreKeyBackupDialog.tsx @@ -9,9 +9,9 @@ Please see LICENSE files in the repository root for full details. import React, { ChangeEvent } from "react"; import { MatrixClient, MatrixError, SecretStorage } from "matrix-js-sdk/src/matrix"; +import { decodeRecoveryKey, KeyBackupInfo } from "matrix-js-sdk/src/crypto-api"; import { IKeyBackupRestoreResult } from "matrix-js-sdk/src/crypto/keybackup"; import { logger } from "matrix-js-sdk/src/logger"; -import { KeyBackupInfo } from "matrix-js-sdk/src/crypto-api"; import { MatrixClientPeg } from "../../../../MatrixClientPeg"; import { _t } from "../../../../languageHandler"; @@ -118,10 +118,24 @@ export default class RestoreKeyBackupDialog extends React.PureComponent<IProps, accessSecretStorage(async (): Promise<void> => {}, /* forceReset = */ true); }; + /** + * Check if the recovery key is valid + * @param recoveryKey + * @private + */ + private isValidRecoveryKey(recoveryKey: string): boolean { + try { + decodeRecoveryKey(recoveryKey); + return true; + } catch (e) { + return false; + } + } + private onRecoveryKeyChange = (e: ChangeEvent<HTMLInputElement>): void => { this.setState({ recoveryKey: e.target.value, - recoveryKeyValid: MatrixClientPeg.safeGet().isValidRecoveryKey(e.target.value), + recoveryKeyValid: this.isValidRecoveryKey(e.target.value), }); }; @@ -184,7 +198,7 @@ export default class RestoreKeyBackupDialog extends React.PureComponent<IProps, { progressCallback: this.progressCallback }, ); if (this.props.keyCallback) { - const key = MatrixClientPeg.safeGet().keyBackupKeyFromRecoveryKey(this.state.recoveryKey); + const key = decodeRecoveryKey(this.state.recoveryKey); this.props.keyCallback(key); } if (!this.props.showSummary) { diff --git a/test/components/views/dialogs/AccessSecretStorageDialog-test.tsx b/test/components/views/dialogs/AccessSecretStorageDialog-test.tsx index 38bc9bf342..c07808ac11 100644 --- a/test/components/views/dialogs/AccessSecretStorageDialog-test.tsx +++ b/test/components/views/dialogs/AccessSecretStorageDialog-test.tsx @@ -58,15 +58,12 @@ describe("AccessSecretStorageDialog", () => { beforeEach(() => { mockClient = getMockClientWithEventEmitter({ - keyBackupKeyFromRecoveryKey: jest.fn(), checkSecretStorageKey: jest.fn(), - isValidRecoveryKey: jest.fn(), }); }); it("Closes the dialog when the form is submitted with a valid key", async () => { mockClient.checkSecretStorageKey.mockResolvedValue(true); - mockClient.isValidRecoveryKey.mockReturnValue(true); const onFinished = jest.fn(); const checkPrivateKey = jest.fn().mockResolvedValue(true); @@ -88,8 +85,8 @@ describe("AccessSecretStorageDialog", () => { const checkPrivateKey = jest.fn().mockResolvedValue(true); renderComponent({ onFinished, checkPrivateKey }); - mockClient.keyBackupKeyFromRecoveryKey.mockImplementation(() => { - throw new Error("that's no key"); + mockClient.checkSecretStorageKey.mockImplementation(() => { + throw new Error("invalid key"); }); await enterSecurityKey(); @@ -115,7 +112,6 @@ describe("AccessSecretStorageDialog", () => { }; const checkPrivateKey = jest.fn().mockResolvedValue(false); renderComponent({ checkPrivateKey, keyInfo }); - mockClient.isValidRecoveryKey.mockReturnValue(false); await enterSecurityKey("Security Phrase"); expect(screen.getByPlaceholderText("Security Phrase")).toHaveValue(securityKey); diff --git a/test/components/views/dialogs/security/RestoreKeyBackupDialog-test.tsx b/test/components/views/dialogs/security/RestoreKeyBackupDialog-test.tsx new file mode 100644 index 0000000000..3e52b473b6 --- /dev/null +++ b/test/components/views/dialogs/security/RestoreKeyBackupDialog-test.tsx @@ -0,0 +1,51 @@ +/* + * Copyright 2024 New Vector Ltd. + * + * 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 { screen, render, waitFor } from "@testing-library/react"; +import userEvent from "@testing-library/user-event"; +// Needed to be able to mock decodeRecoveryKey +// eslint-disable-next-line no-restricted-imports +import * as recoveryKeyModule from "matrix-js-sdk/src/crypto-api/recovery-key"; + +import RestoreKeyBackupDialog from "../../../../../src/components/views/dialogs/security/RestoreKeyBackupDialog.tsx"; +import { stubClient } from "../../../../test-utils"; + +describe("<RestoreKeyBackupDialog />", () => { + beforeEach(() => { + stubClient(); + jest.spyOn(recoveryKeyModule, "decodeRecoveryKey").mockReturnValue(new Uint8Array(32)); + }); + + it("should render", async () => { + const { asFragment } = render(<RestoreKeyBackupDialog onFinished={jest.fn()} />); + await waitFor(() => expect(screen.getByText("Enter Security Key")).toBeInTheDocument()); + expect(asFragment()).toMatchSnapshot(); + }); + + it("should display an error when recovery key is invalid", async () => { + jest.spyOn(recoveryKeyModule, "decodeRecoveryKey").mockImplementation(() => { + throw new Error("Invalid recovery key"); + }); + const { asFragment } = render(<RestoreKeyBackupDialog onFinished={jest.fn()} />); + await waitFor(() => expect(screen.getByText("Enter Security Key")).toBeInTheDocument()); + + await userEvent.type(screen.getByRole("textbox"), "invalid key"); + await waitFor(() => expect(screen.getByText("👎 Not a valid Security Key")).toBeInTheDocument()); + expect(asFragment()).toMatchSnapshot(); + }); + + it("should not raise an error when recovery is valid", async () => { + const { asFragment } = render(<RestoreKeyBackupDialog onFinished={jest.fn()} />); + await waitFor(() => expect(screen.getByText("Enter Security Key")).toBeInTheDocument()); + + await userEvent.type(screen.getByRole("textbox"), "valid key"); + await waitFor(() => expect(screen.getByText("👍 This looks like a valid Security Key!")).toBeInTheDocument()); + expect(asFragment()).toMatchSnapshot(); + }); +}); diff --git a/test/components/views/dialogs/security/__snapshots__/RestoreKeyBackupDialog-test.tsx.snap b/test/components/views/dialogs/security/__snapshots__/RestoreKeyBackupDialog-test.tsx.snap new file mode 100644 index 0000000000..de0bddbe33 --- /dev/null +++ b/test/components/views/dialogs/security/__snapshots__/RestoreKeyBackupDialog-test.tsx.snap @@ -0,0 +1,298 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`<RestoreKeyBackupDialog /> should display an error when recovery key is invalid 1`] = ` +<DocumentFragment> + <div + data-focus-guard="true" + style="width: 1px; height: 0px; padding: 0px; overflow: hidden; position: fixed; top: 1px; left: 1px;" + tabindex="0" + /> + <div + aria-labelledby="mx_BaseDialog_title" + class="mx_RestoreKeyBackupDialog mx_Dialog_fixedWidth" + data-focus-lock-disabled="false" + role="dialog" + > + <div + class="mx_Dialog_header" + > + <h1 + class="mx_Heading_h3 mx_Dialog_title" + id="mx_BaseDialog_title" + > + Enter Security Key + </h1> + </div> + <div + class="mx_RestoreKeyBackupDialog_content" + > + <div> + <p> + <span> + <b> + Warning + </b> + : you should only set up key backup from a trusted computer. + </span> + </p> + <p> + Access your secure message history and set up secure messaging by entering your Security Key. + </p> + <div + class="mx_RestoreKeyBackupDialog_primaryContainer" + > + <input + class="mx_RestoreKeyBackupDialog_recoveryKeyInput" + value="invalid key" + /> + <div + class="mx_RestoreKeyBackupDialog_keyStatus" + > + 👎 Not a valid Security Key + </div> + <div + class="mx_Dialog_buttons" + > + <span + class="mx_Dialog_buttons_row" + > + <button + data-testid="dialog-cancel-button" + type="button" + > + Cancel + </button> + <button + class="mx_Dialog_primary" + data-testid="dialog-primary-button" + disabled="" + type="button" + > + Next + </button> + </span> + </div> + </div> + <span> + If you've forgotten your Security Key you can + <div + class="mx_AccessibleButton mx_AccessibleButton_hasKind mx_AccessibleButton_kind_link_inline" + role="button" + tabindex="0" + > + set up new recovery options + </div> + </span> + </div> + </div> + <div + aria-label="Close dialog" + class="mx_AccessibleButton mx_Dialog_cancelButton" + role="button" + tabindex="0" + /> + </div> + <div + data-focus-guard="true" + style="width: 1px; height: 0px; padding: 0px; overflow: hidden; position: fixed; top: 1px; left: 1px;" + tabindex="0" + /> +</DocumentFragment> +`; + +exports[`<RestoreKeyBackupDialog /> should not raise an error when recovery is valid 1`] = ` +<DocumentFragment> + <div + data-focus-guard="true" + style="width: 1px; height: 0px; padding: 0px; overflow: hidden; position: fixed; top: 1px; left: 1px;" + tabindex="0" + /> + <div + aria-labelledby="mx_BaseDialog_title" + class="mx_RestoreKeyBackupDialog mx_Dialog_fixedWidth" + data-focus-lock-disabled="false" + role="dialog" + > + <div + class="mx_Dialog_header" + > + <h1 + class="mx_Heading_h3 mx_Dialog_title" + id="mx_BaseDialog_title" + > + Enter Security Key + </h1> + </div> + <div + class="mx_RestoreKeyBackupDialog_content" + > + <div> + <p> + <span> + <b> + Warning + </b> + : you should only set up key backup from a trusted computer. + </span> + </p> + <p> + Access your secure message history and set up secure messaging by entering your Security Key. + </p> + <div + class="mx_RestoreKeyBackupDialog_primaryContainer" + > + <input + class="mx_RestoreKeyBackupDialog_recoveryKeyInput" + value="valid key" + /> + <div + class="mx_RestoreKeyBackupDialog_keyStatus" + > + 👍 This looks like a valid Security Key! + </div> + <div + class="mx_Dialog_buttons" + > + <span + class="mx_Dialog_buttons_row" + > + <button + data-testid="dialog-cancel-button" + type="button" + > + Cancel + </button> + <button + class="mx_Dialog_primary" + data-testid="dialog-primary-button" + type="button" + > + Next + </button> + </span> + </div> + </div> + <span> + If you've forgotten your Security Key you can + <div + class="mx_AccessibleButton mx_AccessibleButton_hasKind mx_AccessibleButton_kind_link_inline" + role="button" + tabindex="0" + > + set up new recovery options + </div> + </span> + </div> + </div> + <div + aria-label="Close dialog" + class="mx_AccessibleButton mx_Dialog_cancelButton" + role="button" + tabindex="0" + /> + </div> + <div + data-focus-guard="true" + style="width: 1px; height: 0px; padding: 0px; overflow: hidden; position: fixed; top: 1px; left: 1px;" + tabindex="0" + /> +</DocumentFragment> +`; + +exports[`<RestoreKeyBackupDialog /> should render 1`] = ` +<DocumentFragment> + <div + data-focus-guard="true" + style="width: 1px; height: 0px; padding: 0px; overflow: hidden; position: fixed; top: 1px; left: 1px;" + tabindex="0" + /> + <div + aria-labelledby="mx_BaseDialog_title" + class="mx_RestoreKeyBackupDialog mx_Dialog_fixedWidth" + data-focus-lock-disabled="false" + role="dialog" + > + <div + class="mx_Dialog_header" + > + <h1 + class="mx_Heading_h3 mx_Dialog_title" + id="mx_BaseDialog_title" + > + Enter Security Key + </h1> + </div> + <div + class="mx_RestoreKeyBackupDialog_content" + > + <div> + <p> + <span> + <b> + Warning + </b> + : you should only set up key backup from a trusted computer. + </span> + </p> + <p> + Access your secure message history and set up secure messaging by entering your Security Key. + </p> + <div + class="mx_RestoreKeyBackupDialog_primaryContainer" + > + <input + class="mx_RestoreKeyBackupDialog_recoveryKeyInput" + value="" + /> + <div + class="mx_RestoreKeyBackupDialog_keyStatus" + /> + <div + class="mx_Dialog_buttons" + > + <span + class="mx_Dialog_buttons_row" + > + <button + data-testid="dialog-cancel-button" + type="button" + > + Cancel + </button> + <button + class="mx_Dialog_primary" + data-testid="dialog-primary-button" + disabled="" + type="button" + > + Next + </button> + </span> + </div> + </div> + <span> + If you've forgotten your Security Key you can + <div + class="mx_AccessibleButton mx_AccessibleButton_hasKind mx_AccessibleButton_kind_link_inline" + role="button" + tabindex="0" + > + set up new recovery options + </div> + </span> + </div> + </div> + <div + aria-label="Close dialog" + class="mx_AccessibleButton mx_Dialog_cancelButton" + role="button" + tabindex="0" + /> + </div> + <div + data-focus-guard="true" + style="width: 1px; height: 0px; padding: 0px; overflow: hidden; position: fixed; top: 1px; left: 1px;" + tabindex="0" + /> +</DocumentFragment> +`; From cf8fe20452613a5043570d2d9d0aa8180bff3748 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Thu, 19 Sep 2024 18:03:41 +0100 Subject: [PATCH 09/21] Update dependency express to v4.20.0 [SECURITY] (#26) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- yarn.lock | 83 ++++++++++++++++++++++++++++++++++++++----------------- 1 file changed, 57 insertions(+), 26 deletions(-) diff --git a/yarn.lock b/yarn.lock index f872acbe5f..f2e0b4641b 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3601,10 +3601,10 @@ blurhash@^2.0.3: resolved "https://registry.yarnpkg.com/blurhash/-/blurhash-2.0.5.tgz#efde729fc14a2f03571a6aa91b49cba80d1abe4b" integrity sha512-cRygWd7kGBQO3VEhPiTgq4Wc43ctsM+o46urrmPOiuAe+07fzlSB9OJVdpgDL0jPqXUVQ9ht7aq7kxOeJHRK+w== -body-parser@1.20.2: - version "1.20.2" - resolved "https://registry.yarnpkg.com/body-parser/-/body-parser-1.20.2.tgz#6feb0e21c4724d06de7ff38da36dad4f57a747fd" - integrity sha512-ml9pReCu3M61kGlqoTm2umSXTlRTuGTx0bfYj+uIUKKYycG5NtSbeetV3faSU6R7ajOPw0g/J1PvK4qNy7s5bA== +body-parser@1.20.3: + version "1.20.3" + resolved "https://registry.yarnpkg.com/body-parser/-/body-parser-1.20.3.tgz#1953431221c6fb5cd63c4b36d53fab0928e548c6" + integrity sha512-7rAxByjUMqQ3/bHJy7D6OGXvx/MMc4IqBn/X0fcM1QUcAItpZrBEYhWGem+tzXH90c+G01ypMcYJBO9Y30203g== dependencies: bytes "3.1.2" content-type "~1.0.5" @@ -3614,7 +3614,7 @@ body-parser@1.20.2: http-errors "2.0.0" iconv-lite "0.4.24" on-finished "2.4.1" - qs "6.11.0" + qs "6.13.0" raw-body "2.5.2" type-is "~1.6.18" unpipe "1.0.0" @@ -4443,6 +4443,11 @@ encodeurl@~1.0.2: resolved "https://registry.yarnpkg.com/encodeurl/-/encodeurl-1.0.2.tgz#ad3ff4c86ec2d029322f5a02c3a9a606c95b3f59" integrity sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w== +encodeurl@~2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/encodeurl/-/encodeurl-2.0.0.tgz#7b8ea898077d7e409d3ac45474ea38eaf0857a58" + integrity sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg== + entities@^4.2.0: version "4.4.0" resolved "https://registry.yarnpkg.com/entities/-/entities-4.4.0.tgz#97bdaba170339446495e653cfd2db78962900174" @@ -5009,36 +5014,36 @@ expect@^29.0.0, expect@^29.7.0: jest-util "^29.7.0" express@^4.18.2: - version "4.19.2" - resolved "https://registry.yarnpkg.com/express/-/express-4.19.2.tgz#e25437827a3aa7f2a827bc8171bbbb664a356465" - integrity sha512-5T6nhjsT+EOMzuck8JjBHARTHfMht0POzlA60WV2pMD3gyXw2LZnZ+ueGdNxG+0calOJcWKbpFcuzLZ91YWq9Q== + version "4.20.0" + resolved "https://registry.yarnpkg.com/express/-/express-4.20.0.tgz#f1d08e591fcec770c07be4767af8eb9bcfd67c48" + integrity sha512-pLdae7I6QqShF5PnNTCVn4hI91Dx0Grkn2+IAsMTgMIKuQVte2dN9PeGSSAME2FR8anOhVA62QDIUaWVfEXVLw== dependencies: accepts "~1.3.8" array-flatten "1.1.1" - body-parser "1.20.2" + body-parser "1.20.3" content-disposition "0.5.4" content-type "~1.0.4" cookie "0.6.0" cookie-signature "1.0.6" debug "2.6.9" depd "2.0.0" - encodeurl "~1.0.2" + encodeurl "~2.0.0" escape-html "~1.0.3" etag "~1.8.1" finalhandler "1.2.0" fresh "0.5.2" http-errors "2.0.0" - merge-descriptors "1.0.1" + merge-descriptors "1.0.3" methods "~1.1.2" on-finished "2.4.1" parseurl "~1.3.3" - path-to-regexp "0.1.7" + path-to-regexp "0.1.10" proxy-addr "~2.0.7" qs "6.11.0" range-parser "~1.2.1" safe-buffer "5.2.1" - send "0.18.0" - serve-static "1.15.0" + send "0.19.0" + serve-static "1.16.0" setprototypeof "1.2.0" statuses "2.0.1" type-is "~1.6.18" @@ -7090,10 +7095,10 @@ meow@^13.2.0: resolved "https://registry.yarnpkg.com/meow/-/meow-13.2.0.tgz#6b7d63f913f984063b3cc261b6e8800c4cd3474f" integrity sha512-pxQJQzB6djGPXh08dacEloMFopsOqGVRKFPYvPOt9XDZ1HasbgDZA74CJGreSU4G3Ak7EFJGoiH2auq+yXISgA== -merge-descriptors@1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/merge-descriptors/-/merge-descriptors-1.0.1.tgz#b00aaa556dd8b44568150ec9d1b953f3f90cbb61" - integrity sha512-cCi6g3/Zr1iqQi6ySbseM1Xvooa98N0w31jzUYrXPX2xqObmFGHJ0tQ5u74H3mVh7wLouTseZyYIq39g8cNp1w== +merge-descriptors@1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/merge-descriptors/-/merge-descriptors-1.0.3.tgz#d80319a65f3c7935351e5cfdac8f9318504dbed5" + integrity sha512-gaNvAS7TZ897/rVaZ0nMtAyxNyi/pdbjbAwUpFQpN70GqnVfOiXpeUUMKRBmzXaSQ8DdTX4/0ms62r2K+hE6mQ== merge-stream@^2.0.0: version "2.0.0" @@ -7570,10 +7575,10 @@ path-scurry@^2.0.0: lru-cache "^11.0.0" minipass "^7.1.2" -path-to-regexp@0.1.7: - version "0.1.7" - resolved "https://registry.yarnpkg.com/path-to-regexp/-/path-to-regexp-0.1.7.tgz#df604178005f522f15eb4490e7247a1bfaa67f8c" - integrity sha512-5DFkuoqlv1uYQKxy8omFBeJPQcdoE07Kv2sferDCrAq1ohOU+MSDswDIbnx3YAM60qIOnYa53wBhXW0EbMonrQ== +path-to-regexp@0.1.10: + version "0.1.10" + resolved "https://registry.yarnpkg.com/path-to-regexp/-/path-to-regexp-0.1.10.tgz#67e9108c5c0551b9e5326064387de4763c4d5f8b" + integrity sha512-7lf7qcQidTku0Gu3YDPc8DJ1q7OOucfa/BSsIwjuh56VU7katFvuM8hULfkwB3Fns/rsVF7PwPKVw1sl5KQS9w== path-to-regexp@^2.2.1: version "2.4.0" @@ -7854,6 +7859,13 @@ qs@6.11.0: dependencies: side-channel "^1.0.4" +qs@6.13.0: + version "6.13.0" + resolved "https://registry.yarnpkg.com/qs/-/qs-6.13.0.tgz#6ca3bd58439f7e245655798997787b0d88a51906" + integrity sha512-+38qI9SOr8tfZ4QmJNplMUxqjbe7LKvvZgWdExBOmd+egZTtjLB67Gu0HRX3u/XOq7UU2Nx6nsjvS16Z9uwfpg== + dependencies: + side-channel "^1.0.6" + querystring@^0.2.0: version "0.2.1" resolved "https://registry.yarnpkg.com/querystring/-/querystring-0.2.1.tgz#40d77615bb09d16902a85c3e38aa8b5ed761c2dd" @@ -8445,10 +8457,29 @@ send@0.18.0: range-parser "~1.2.1" statuses "2.0.1" -serve-static@1.15.0: - version "1.15.0" - resolved "https://registry.yarnpkg.com/serve-static/-/serve-static-1.15.0.tgz#faaef08cffe0a1a62f60cad0c4e513cff0ac9540" - integrity sha512-XGuRDNjXUijsUL0vl6nSD7cwURuzEgglbOaFuZM9g3kwDXOWVTck0jLzjPzGD+TazWbboZYu52/9/XPdUgne9g== +send@0.19.0: + version "0.19.0" + resolved "https://registry.yarnpkg.com/send/-/send-0.19.0.tgz#bbc5a388c8ea6c048967049dbeac0e4a3f09d7f8" + integrity sha512-dW41u5VfLXu8SJh5bwRmyYUbAoSB3c9uQh6L8h/KtsFREPWpbX1lrljJo186Jc4nmci/sGUZ9a0a0J2zgfq2hw== + dependencies: + debug "2.6.9" + depd "2.0.0" + destroy "1.2.0" + encodeurl "~1.0.2" + escape-html "~1.0.3" + etag "~1.8.1" + fresh "0.5.2" + http-errors "2.0.0" + mime "1.6.0" + ms "2.1.3" + on-finished "2.4.1" + range-parser "~1.2.1" + statuses "2.0.1" + +serve-static@1.16.0: + version "1.16.0" + resolved "https://registry.yarnpkg.com/serve-static/-/serve-static-1.16.0.tgz#2bf4ed49f8af311b519c46f272bf6ac3baf38a92" + integrity sha512-pDLK8zwl2eKaYrs8mrPZBJua4hMplRWJ1tIFksVC3FtBEBnl8dxgeHtsaMS8DhS9i4fLObaon6ABoc4/hQGdPA== dependencies: encodeurl "~1.0.2" escape-html "~1.0.3" From 5058d664ddd4ecaa89a4340ee7265d597f7e8c24 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Thu, 19 Sep 2024 18:18:38 +0100 Subject: [PATCH 10/21] Update Sibz/github-status-action digest to faaa4d9 (#63) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- .github/workflows/tests.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index e306b32959..22a02779b3 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -96,7 +96,7 @@ jobs: needs: jest steps: - name: Skip SonarCloud - uses: Sibz/github-status-action@071b5370da85afbb16637d6eed8524a06bc2053e # v1 + uses: Sibz/github-status-action@faaa4d96fecf273bd762985e0e7f9f933c774918 # v1 with: authToken: ${{ secrets.GITHUB_TOKEN }} state: success From ed7e02ab790fc57950a471b4c973b2a257bcce39 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Thu, 19 Sep 2024 21:21:12 +0000 Subject: [PATCH 11/21] Update dependency stylelint-scss to v6.6.0 (#70) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- yarn.lock | 27 ++++++++++++++++----------- 1 file changed, 16 insertions(+), 11 deletions(-) diff --git a/yarn.lock b/yarn.lock index f2e0b4641b..7862b65d6e 100644 --- a/yarn.lock +++ b/yarn.lock @@ -7683,7 +7683,7 @@ postcss-media-query-parser@^0.2.3: resolved "https://registry.yarnpkg.com/postcss-media-query-parser/-/postcss-media-query-parser-0.2.3.tgz#27b39c6f4d94f81b1a73b8f76351c609e5cef244" integrity sha512-3sOlxmbKcSHMjlUXQZKQ06jOswE7oVkXPxmZdoB1r5l0q6gTFTQSHxNxOrCccElbW7dxNytifNEo8qidX2Vsig== -postcss-resolve-nested-selector@^0.1.4, postcss-resolve-nested-selector@^0.1.6: +postcss-resolve-nested-selector@^0.1.6: version "0.1.6" resolved "https://registry.yarnpkg.com/postcss-resolve-nested-selector/-/postcss-resolve-nested-selector-0.1.6.tgz#3d84dec809f34de020372c41b039956966896686" integrity sha512-0sglIs9Wmkzbr8lQwEyIzlDOOC9bGmfVKcJTaxv3vMmd3uo4o4DerC3En0bnmgceeql9BfC8hRkp7cg0fjdVqw== @@ -7698,7 +7698,7 @@ postcss-scss@^4.0.4: resolved "https://registry.yarnpkg.com/postcss-scss/-/postcss-scss-4.0.9.tgz#a03c773cd4c9623cb04ce142a52afcec74806685" integrity sha512-AjKOeiwAitL/MXxQW2DliT28EKukvvbEWx3LBmJIRN8KfBGZbRTxNYW0kSqi1COiTZ57nZ9NW06S6ux//N1c9A== -postcss-selector-parser@^6.1.1, postcss-selector-parser@^6.1.2: +postcss-selector-parser@^6.1.2: version "6.1.2" resolved "https://registry.yarnpkg.com/postcss-selector-parser/-/postcss-selector-parser-6.1.2.tgz#27ecb41fb0e3b6ba7a1ec84fff347f734c7929de" integrity sha512-Q8qQfPiZ+THO/3ZrOrO0cJJKfpYCagtMUkXbnEfmgUjwXg6z/WBeOyS9APBBPCTSiDV+s4SwQGu8yFsiMRIudg== @@ -8602,16 +8602,21 @@ slice-ansi@^7.1.0: ansi-styles "^6.2.1" is-fullwidth-code-point "^5.0.0" -source-map-js@^1.0.1, source-map-js@^1.2.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/source-map-js/-/source-map-js-1.2.0.tgz#16b809c162517b5b8c3e7dcd315a2a5c2612b2af" - integrity sha512-itJW8lvSA0TXEphiRoawsCksnlf8SyvmFzIhltqAHluXd88pkCd+cXJVHTDwdCr0IzwptSm035IHQktUu1QUMg== +source-map-js@^1.0.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/source-map-js/-/source-map-js-1.2.1.tgz#1ce5650fddd87abc099eda37dcff024c2667ae46" + integrity sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA== source-map-js@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/source-map-js/-/source-map-js-1.0.2.tgz#adbc361d9c62df380125e7f161f71c826f1e490c" integrity sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw== +source-map-js@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/source-map-js/-/source-map-js-1.2.0.tgz#16b809c162517b5b8c3e7dcd315a2a5c2612b2af" + integrity sha512-itJW8lvSA0TXEphiRoawsCksnlf8SyvmFzIhltqAHluXd88pkCd+cXJVHTDwdCr0IzwptSm035IHQktUu1QUMg== + source-map-support@0.5.13: version "0.5.13" resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.5.13.tgz#31b24a9c2e73c2de85066c0feb7d44767ed52932" @@ -8872,16 +8877,16 @@ stylelint-config-standard@^36.0.0: stylelint-config-recommended "^14.0.1" stylelint-scss@^6.0.0: - version "6.5.1" - resolved "https://registry.yarnpkg.com/stylelint-scss/-/stylelint-scss-6.5.1.tgz#bcb6a4ada71a0adbf181e155548e5f25ee4aeece" - integrity sha512-ZLqdqihm6uDYkrsOeD6YWb+stZI8Wn92kUNDhE4M+g9g1aCnRv0JlOrttFiAJJwaNzpdQgX3YJb5vDQXVuO9Ww== + version "6.7.0" + resolved "https://registry.yarnpkg.com/stylelint-scss/-/stylelint-scss-6.7.0.tgz#df9c2bcd20c555c5670914f23bb983c94bfbb0e3" + integrity sha512-RFIa2A+pVWS5wjNT+whtK7wsbZEWazyqesCuSaPbPlZ8lh2TujwVJSnCYJijg6ChZzwI8pZPRZS1L6A9aCbXDg== dependencies: css-tree "2.3.1" is-plain-object "5.0.0" known-css-properties "^0.34.0" postcss-media-query-parser "^0.2.3" - postcss-resolve-nested-selector "^0.1.4" - postcss-selector-parser "^6.1.1" + postcss-resolve-nested-selector "^0.1.6" + postcss-selector-parser "^6.1.2" postcss-value-parser "^4.2.0" stylelint@^16.1.0: From d4c942d81367a76cd606efccdb07bbd6528d538f Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Thu, 19 Sep 2024 21:58:55 +0000 Subject: [PATCH 12/21] Update playwright monorepo to v1.47.1 (#73) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- yarn.lock | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/yarn.lock b/yarn.lock index 7862b65d6e..e4b851b610 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2001,11 +2001,11 @@ integrity sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg== "@playwright/test@^1.40.1": - version "1.46.1" - resolved "https://registry.yarnpkg.com/@playwright/test/-/test-1.46.1.tgz#a8dfdcd623c4c23bb1b7ea588058aad41055c188" - integrity sha512-Fq6SwLujA/DOIvNC2EL/SojJnkKf/rAwJ//APpJJHRyMi1PdKrY3Az+4XNQ51N4RTbItbIByQ0jgd1tayq1aeA== + version "1.47.1" + resolved "https://registry.yarnpkg.com/@playwright/test/-/test-1.47.1.tgz#568a46229a5aef54b74977297a7946bb5ac4b67b" + integrity sha512-dbWpcNQZ5nj16m+A5UNScYx7HX5trIy7g4phrcitn+Nk83S32EBX/CLU4hiF4RGKX/yRc93AAqtfaXB7JWBd4Q== dependencies: - playwright "1.46.1" + playwright "1.47.1" "@radix-ui/primitive@1.0.1": version "1.0.1" @@ -7637,17 +7637,17 @@ pkg-dir@^4.2.0: dependencies: find-up "^4.0.0" -playwright-core@1.46.1, playwright-core@^1.45.1: - version "1.46.1" - resolved "https://registry.yarnpkg.com/playwright-core/-/playwright-core-1.46.1.tgz#28f3ab35312135dda75b0c92a3e5c0e7edb9cc8b" - integrity sha512-h9LqIQaAv+CYvWzsZ+h3RsrqCStkBHlgo6/TJlFst3cOTlLghBQlJwPOZKQJTKNaD3QIB7aAVQ+gfWbN3NXB7A== +playwright-core@1.47.1, playwright-core@^1.45.1: + version "1.47.1" + resolved "https://registry.yarnpkg.com/playwright-core/-/playwright-core-1.47.1.tgz#bb45bdfb0d48412c535501aa3805867282857df8" + integrity sha512-i1iyJdLftqtt51mEk6AhYFaAJCDx0xQ/O5NU8EKaWFgMjItPVma542Nh/Aq8aLCjIJSzjaiEQGW/nyqLkGF1OQ== -playwright@1.46.1: - version "1.46.1" - resolved "https://registry.yarnpkg.com/playwright/-/playwright-1.46.1.tgz#ea562bc48373648e10420a10c16842f0b227c218" - integrity sha512-oPcr1yqoXLCkgKtD5eNUPLiN40rYEM39odNpIb6VE6S7/15gJmA1NzVv6zJYusV0e7tzvkU/utBFNa/Kpxmwng== +playwright@1.47.1: + version "1.47.1" + resolved "https://registry.yarnpkg.com/playwright/-/playwright-1.47.1.tgz#cdc1116f5265b8d2ff7be0d8942d49900634dc6c" + integrity sha512-SUEKi6947IqYbKxRiqnbUobVZY4bF1uu+ZnZNJX9DfU1tlf2UhWfvVjLf01pQx9URsOr18bFVUKXmanYWhbfkw== dependencies: - playwright-core "1.46.1" + playwright-core "1.47.1" optionalDependencies: fsevents "2.3.2" From b055908fa404e39333000dc4f2d679944a4dcb42 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Thu, 19 Sep 2024 22:00:02 +0000 Subject: [PATCH 13/21] Update dependency css-tree to v3 (#74) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- package.json | 2 +- yarn.lock | 13 +++++++++++++ 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/package.json b/package.json index 00301bef50..30a16036ff 100644 --- a/package.json +++ b/package.json @@ -91,7 +91,7 @@ "classnames": "^2.2.6", "commonmark": "^0.31.0", "counterpart": "^0.18.6", - "css-tree": "^2.3.1", + "css-tree": "^3.0.0", "diff-dom": "^5.0.0", "diff-match-patch": "^1.0.5", "emojibase-regex": "15.3.2", diff --git a/yarn.lock b/yarn.lock index e4b851b610..5bb6e4c0ac 100644 --- a/yarn.lock +++ b/yarn.lock @@ -4059,6 +4059,14 @@ css-tree@2.3.1, css-tree@^2.3.1: mdn-data "2.0.30" source-map-js "^1.0.1" +css-tree@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/css-tree/-/css-tree-3.0.0.tgz#079c7b87e465a28cedbc826502f9a227213db0f3" + integrity sha512-o88DVQ6GzsABn1+6+zo2ct801dBO5OASVyxbbvA2W20ue2puSh/VOuqUj90eUeMSX/xqGqBmOKiRQN7tJOuBXw== + dependencies: + mdn-data "2.10.0" + source-map-js "^1.0.1" + css.escape@^1.5.1: version "1.5.1" resolved "https://registry.yarnpkg.com/css.escape/-/css.escape-1.5.1.tgz#42e27d4fa04ae32f931a4b4d4191fa9cddee97cb" @@ -7070,6 +7078,11 @@ mdn-data@2.0.30: resolved "https://registry.yarnpkg.com/mdn-data/-/mdn-data-2.0.30.tgz#ce4df6f80af6cfbe218ecd5c552ba13c4dfa08cc" integrity sha512-GaqWWShW4kv/G9IEucWScBx9G1/vsFZZJUO+tD26M8J8z3Kw5RDQjaoZe03YAClgeS/SWPOcb4nkFBTEi5DUEA== +mdn-data@2.10.0: + version "2.10.0" + resolved "https://registry.yarnpkg.com/mdn-data/-/mdn-data-2.10.0.tgz#701da407f8fbc7a42aa0ba0c149ec897daef8986" + integrity sha512-qq7C3EtK3yJXMwz1zAab65pjl+UhohqMOctTgcqjLOWABqmwj+me02LSsCuEUxnst9X1lCBpoE0WArGKgdGDzw== + mdurl@~1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/mdurl/-/mdurl-1.0.1.tgz#fe85b2ec75a59037f2adfec100fd6c601761152e" From 4be533813e1f85f2cef1c415f80b8e7d28fd32ec Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Thu, 19 Sep 2024 22:42:29 +0000 Subject: [PATCH 14/21] Update dependency @sentry/browser to v8.30.0 (#69) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- yarn.lock | 110 +++++++++++++++++++++++++++--------------------------- 1 file changed, 55 insertions(+), 55 deletions(-) diff --git a/yarn.lock b/yarn.lock index 5bb6e4c0ac..8209709b1a 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2347,76 +2347,76 @@ resolved "https://registry.yarnpkg.com/@radix-ui/rect/-/rect-1.1.0.tgz#f817d1d3265ac5415dadc67edab30ae196696438" integrity sha512-A9+lCBZoaMJlVKcRBz2YByCG+Cp2t6nAnMnNba+XiWxnj6r4JUFqfsgwocMBZU9LPtdxC6wB56ySYpc7LQIoJg== -"@sentry-internal/browser-utils@8.28.0": - version "8.28.0" - resolved "https://registry.yarnpkg.com/@sentry-internal/browser-utils/-/browser-utils-8.28.0.tgz#bddc58c154e898195d45e971e058e237085bbcc2" - integrity sha512-tE9++KEy8SlqibTmYymuxFVAnutsXBqrwQ936WJbjaMfkqXiro7C1El0ybkprskd0rKS7kln20Q6nQlNlMEoTA== +"@sentry-internal/browser-utils@8.30.0": + version "8.30.0" + resolved "https://registry.yarnpkg.com/@sentry-internal/browser-utils/-/browser-utils-8.30.0.tgz#eb68c79556ffb864eb5924a53affde52f2b77362" + integrity sha512-pwX+awNWaxSOAsBLVLqc1+Hw+Fm1Nci9mbKFA6Ed5YzCG049PnBVQwugpmx2dcyyCqJpORhcIqb9jHdCkYmCiA== dependencies: - "@sentry/core" "8.28.0" - "@sentry/types" "8.28.0" - "@sentry/utils" "8.28.0" + "@sentry/core" "8.30.0" + "@sentry/types" "8.30.0" + "@sentry/utils" "8.30.0" -"@sentry-internal/feedback@8.28.0": - version "8.28.0" - resolved "https://registry.yarnpkg.com/@sentry-internal/feedback/-/feedback-8.28.0.tgz#f278548ead037ad38e54d24b1afcdc1f711c5715" - integrity sha512-5vYunPCDBLCJ8QNnhepacdYheiN+UtYxpGAIaC/zjBC1nDuBgWs+TfKPo1UlO/1sesfgs9ibpxtShOweucL61g== +"@sentry-internal/feedback@8.30.0": + version "8.30.0" + resolved "https://registry.yarnpkg.com/@sentry-internal/feedback/-/feedback-8.30.0.tgz#6f78a245298502e4cc5ce77313dde6965abfecfe" + integrity sha512-ParFRxQY6helxkwUDmro77Wc5uSIC6rZos88jYMrYwFmoTJaNWf4lDzPyECfdSiSYyzSMZk4dorSUN85Ul7DCg== dependencies: - "@sentry/core" "8.28.0" - "@sentry/types" "8.28.0" - "@sentry/utils" "8.28.0" + "@sentry/core" "8.30.0" + "@sentry/types" "8.30.0" + "@sentry/utils" "8.30.0" -"@sentry-internal/replay-canvas@8.28.0": - version "8.28.0" - resolved "https://registry.yarnpkg.com/@sentry-internal/replay-canvas/-/replay-canvas-8.28.0.tgz#6a08541f9fecd912b7334c693a403469c9e34a89" - integrity sha512-RfpYHDHMUKGeEdx41QtHITjEn6P3tGaDPHvatqdrD3yv4j+wbJ6laX1PrIxCpGFUtjdzkqi/KUcvUd2kzbH/FA== +"@sentry-internal/replay-canvas@8.30.0": + version "8.30.0" + resolved "https://registry.yarnpkg.com/@sentry-internal/replay-canvas/-/replay-canvas-8.30.0.tgz#3630eec14d23b1fd368d8c331ee695aa5bb41425" + integrity sha512-y/QqcvchhtMlVA6eOZicIfTxtZarazQZJuFW0018ynPxBTiuuWSxMCLqduulXUYsFejfD8/eKHb3BpCIFdDYjg== dependencies: - "@sentry-internal/replay" "8.28.0" - "@sentry/core" "8.28.0" - "@sentry/types" "8.28.0" - "@sentry/utils" "8.28.0" + "@sentry-internal/replay" "8.30.0" + "@sentry/core" "8.30.0" + "@sentry/types" "8.30.0" + "@sentry/utils" "8.30.0" -"@sentry-internal/replay@8.28.0": - version "8.28.0" - resolved "https://registry.yarnpkg.com/@sentry-internal/replay/-/replay-8.28.0.tgz#a84523066ab363239ef6b4180726908cab510e5f" - integrity sha512-70jvzzOL5O74gahgXKyRkZgiYN93yly5gq+bbj4/6NRQ+EtPd285+ccy0laExdfyK0ugvvwD4v+1MQit52OAsg== +"@sentry-internal/replay@8.30.0": + version "8.30.0" + resolved "https://registry.yarnpkg.com/@sentry-internal/replay/-/replay-8.30.0.tgz#6a4a8bd551a16ea5f77f913acbccd88061868c84" + integrity sha512-/KFre+BrovPCiovgAu5N1ErJtkDVzkJA5hV3Jw011AlxRWxrmPwu6+9sV9/rn3tqYAGyq6IggYqeIOHhLh1Ihg== dependencies: - "@sentry-internal/browser-utils" "8.28.0" - "@sentry/core" "8.28.0" - "@sentry/types" "8.28.0" - "@sentry/utils" "8.28.0" + "@sentry-internal/browser-utils" "8.30.0" + "@sentry/core" "8.30.0" + "@sentry/types" "8.30.0" + "@sentry/utils" "8.30.0" "@sentry/browser@^8.0.0": - version "8.28.0" - resolved "https://registry.yarnpkg.com/@sentry/browser/-/browser-8.28.0.tgz#e3d28e7a917c212418c887b4fabacc6ed88baea8" - integrity sha512-i/gjMYzIGQiPFH1pCbdnTwH9xs9mTAqzN+goP3GWX5a58frc7h8vxyA/5z0yMd0aCW6U8mVxnoAT72vGbKbx0g== + version "8.30.0" + resolved "https://registry.yarnpkg.com/@sentry/browser/-/browser-8.30.0.tgz#3c6d5ef62d7daca2873b47f59b136c33941b56de" + integrity sha512-M+tKqawH9S3CqlAIcqdZcHbcsNQkEa9MrPqPCYvXco3C4LRpNizJP2XwBiGQY2yK+fOSvbaWpPtlI938/wuRZQ== dependencies: - "@sentry-internal/browser-utils" "8.28.0" - "@sentry-internal/feedback" "8.28.0" - "@sentry-internal/replay" "8.28.0" - "@sentry-internal/replay-canvas" "8.28.0" - "@sentry/core" "8.28.0" - "@sentry/types" "8.28.0" - "@sentry/utils" "8.28.0" + "@sentry-internal/browser-utils" "8.30.0" + "@sentry-internal/feedback" "8.30.0" + "@sentry-internal/replay" "8.30.0" + "@sentry-internal/replay-canvas" "8.30.0" + "@sentry/core" "8.30.0" + "@sentry/types" "8.30.0" + "@sentry/utils" "8.30.0" -"@sentry/core@8.28.0": - version "8.28.0" - resolved "https://registry.yarnpkg.com/@sentry/core/-/core-8.28.0.tgz#dd28fa913c296b443d4070f147c63e81edf429c8" - integrity sha512-+If9uubvpZpvaQQw4HLiKPhrSS9/KcoA/AcdQkNm+5CVwAoOmDPtyYfkPBgfo2hLZnZQqR1bwkz/PrNoOm+gqA== +"@sentry/core@8.30.0": + version "8.30.0" + resolved "https://registry.yarnpkg.com/@sentry/core/-/core-8.30.0.tgz#f929e42e9a537bfa3eb6024082714e9ab98d822b" + integrity sha512-CJ/FuWLw0QEKGKXGL/nm9eaOdajEcmPekLuHAuOCxID7N07R9l9laz3vFbAkUZ97GGDv3sYrJZgywfY3Moropg== dependencies: - "@sentry/types" "8.28.0" - "@sentry/utils" "8.28.0" + "@sentry/types" "8.30.0" + "@sentry/utils" "8.30.0" -"@sentry/types@8.28.0": - version "8.28.0" - resolved "https://registry.yarnpkg.com/@sentry/types/-/types-8.28.0.tgz#a1cfc004d5714679cb3fed06c27298b0275d13b5" - integrity sha512-hOfqfd92/AzBrEdMgmmV1VfOXJbIfleFTnerRl0mg/+CcNgP/6+Fdonp354TD56ouWNF2WkOM6sEKSXMWp6SEQ== +"@sentry/types@8.30.0": + version "8.30.0" + resolved "https://registry.yarnpkg.com/@sentry/types/-/types-8.30.0.tgz#5f5011f5b16bafd30a039ca5e8c337e948c703fb" + integrity sha512-kgWW2BCjBmVlSQRG32GonHEVyeDbys74xf9mLPvynwHTgw3+NUlNAlEdu05xnb2ow4bCTHfbkS5G1zRgyv5k4Q== -"@sentry/utils@8.28.0": - version "8.28.0" - resolved "https://registry.yarnpkg.com/@sentry/utils/-/utils-8.28.0.tgz#0feb46015033879b2a3cee4c0661386610025f47" - integrity sha512-smhk7PJpvDMQ2DB5p2qn9UeoUHdU41IgjMmS2xklZpa8tjzBTxDeWpGvrX2fuH67D9bAJuLC/XyZjJCHLoEW5g== +"@sentry/utils@8.30.0": + version "8.30.0" + resolved "https://registry.yarnpkg.com/@sentry/utils/-/utils-8.30.0.tgz#2343dd8593ea83890b3e0d792ed3fa257955a26b" + integrity sha512-wZxU2HWlzsnu8214Xy7S7cRIuD6h8Z5DnnkojJfX0i0NLooepZQk2824el1Q13AakLb7/S8CHSHXOMnCtoSduw== dependencies: - "@sentry/types" "8.28.0" + "@sentry/types" "8.30.0" "@sinclair/typebox@^0.27.8": version "0.27.8" From 1f5571062ea8ffc7d89f6adf6b57ecaac7c333be Mon Sep 17 00:00:00 2001 From: David Langley <davidl@element.io> Date: Fri, 20 Sep 2024 12:24:39 +0100 Subject: [PATCH 15/21] Mobile registration optimizations and tests (#62) * Mobile registration optimizations - don't autocaptialize or autocorrect on username field - show each password field in their own row - improve position of tooltip on mobile so that it's visible * Use optional prop rather than default prop. * Redirect to welcome screen if mobile_registration is requested but not enabled in the config. * autocorrect value should be "off" * Add unit tests for mobile registration * Fix test typo * Fix typo --- src/components/structures/MatrixChat.tsx | 14 +++--- .../structures/auth/Registration.tsx | 7 ++- src/components/views/auth/EmailField.tsx | 3 ++ .../views/auth/PassphraseConfirmField.tsx | 4 +- src/components/views/auth/PassphraseField.tsx | 3 ++ .../views/auth/RegistrationForm.tsx | 37 +++++++++++++-- src/components/views/elements/Field.tsx | 7 ++- .../components/structures/MatrixChat-test.tsx | 39 +++++++++++++++ .../structures/auth/Registration-test.tsx | 47 +++++++++++++++++-- 9 files changed, 142 insertions(+), 19 deletions(-) diff --git a/src/components/structures/MatrixChat.tsx b/src/components/structures/MatrixChat.tsx index 8e0eaabe4f..1726c8462d 100644 --- a/src/components/structures/MatrixChat.tsx +++ b/src/components/structures/MatrixChat.tsx @@ -952,18 +952,20 @@ export default class MatrixChat extends React.PureComponent<IProps, IState> { } private async startRegistration(params: { [key: string]: string }, isMobileRegistration?: boolean): Promise<void> { - if (!SettingsStore.getValue(UIFeature.Registration)) { + // If registration is disabled or mobile registration is requested but not enabled in settings redirect to the welcome screen + if ( + !SettingsStore.getValue(UIFeature.Registration) || + (isMobileRegistration && !SettingsStore.getValue("Registration.mobileRegistrationHelper")) + ) { this.showScreen("welcome"); return; } - const isMobileRegistrationAllowed = - isMobileRegistration && SettingsStore.getValue("Registration.mobileRegistrationHelper"); const newState: Partial<IState> = { view: Views.REGISTER, }; - if (isMobileRegistrationAllowed && params.hs_url) { + if (isMobileRegistration && params.hs_url) { try { const config = await AutoDiscoveryUtils.validateServerConfigWithStaticUrls(params.hs_url); newState.serverConfig = config; @@ -992,12 +994,12 @@ export default class MatrixChat extends React.PureComponent<IProps, IState> { newState.register_id_sid = params.sid; } - newState.isMobileRegistration = isMobileRegistrationAllowed; + newState.isMobileRegistration = isMobileRegistration; this.setStateForNewView(newState); ThemeController.isLogin = true; this.themeWatcher.recheck(); - this.notifyNewScreen(isMobileRegistrationAllowed ? "mobile_register" : "register"); + this.notifyNewScreen(isMobileRegistration ? "mobile_register" : "register"); } // switch view to the given room diff --git a/src/components/structures/auth/Registration.tsx b/src/components/structures/auth/Registration.tsx index 2dc9125362..0ae5c93346 100644 --- a/src/components/structures/auth/Registration.tsx +++ b/src/components/structures/auth/Registration.tsx @@ -627,6 +627,7 @@ export default class Registration extends React.Component<IProps, IState> { serverConfig={this.props.serverConfig} canSubmit={!this.state.serverErrorIsFatal} matrixClient={this.state.matrixClient} + mobileRegister={this.props.mobileRegister} /> </React.Fragment> ); @@ -779,7 +780,11 @@ export default class Registration extends React.Component<IProps, IState> { ); } if (this.props.mobileRegister) { - return <div className="mx_MobileRegister_body">{body}</div>; + return ( + <div className="mx_MobileRegister_body" data-testid="mobile-register"> + {body} + </div> + ); } return ( <AuthPage> diff --git a/src/components/views/auth/EmailField.tsx b/src/components/views/auth/EmailField.tsx index e14e3920fd..acd5597259 100644 --- a/src/components/views/auth/EmailField.tsx +++ b/src/components/views/auth/EmailField.tsx @@ -12,6 +12,7 @@ import Field, { IInputProps } from "../elements/Field"; import { _t, _td, TranslationKey } from "../../../languageHandler"; import withValidation, { IFieldState, IValidationResult } from "../elements/Validation"; import * as Email from "../../../email"; +import { Alignment } from "../elements/Tooltip"; interface IProps extends Omit<IInputProps, "onValidate" | "element"> { id?: string; @@ -22,6 +23,7 @@ interface IProps extends Omit<IInputProps, "onValidate" | "element"> { label: TranslationKey; labelRequired: TranslationKey; labelInvalid: TranslationKey; + tooltipAlignment?: Alignment; // When present, completely overrides the default validation rules. validationRules?: (fieldState: IFieldState) => Promise<IValidationResult>; @@ -77,6 +79,7 @@ class EmailField extends PureComponent<IProps> { autoFocus={this.props.autoFocus} onChange={this.props.onChange} onValidate={this.onValidate} + tooltipAlignment={this.props.tooltipAlignment} /> ); } diff --git a/src/components/views/auth/PassphraseConfirmField.tsx b/src/components/views/auth/PassphraseConfirmField.tsx index b72f61310d..ec26099ded 100644 --- a/src/components/views/auth/PassphraseConfirmField.tsx +++ b/src/components/views/auth/PassphraseConfirmField.tsx @@ -11,6 +11,7 @@ import React, { PureComponent, RefCallback, RefObject } from "react"; import Field, { IInputProps } from "../elements/Field"; import withValidation, { IFieldState, IValidationResult } from "../elements/Validation"; import { _t, _td, TranslationKey } from "../../../languageHandler"; +import { Alignment } from "../elements/Tooltip"; interface IProps extends Omit<IInputProps, "onValidate" | "label" | "element"> { id?: string; @@ -22,7 +23,7 @@ interface IProps extends Omit<IInputProps, "onValidate" | "label" | "element"> { label: TranslationKey; labelRequired: TranslationKey; labelInvalid: TranslationKey; - + tooltipAlignment?: Alignment; onChange(ev: React.FormEvent<HTMLElement>): void; onValidate?(result: IValidationResult): void; } @@ -70,6 +71,7 @@ class PassphraseConfirmField extends PureComponent<IProps> { onChange={this.props.onChange} onValidate={this.onValidate} autoFocus={this.props.autoFocus} + tooltipAlignment={this.props.tooltipAlignment} /> ); } diff --git a/src/components/views/auth/PassphraseField.tsx b/src/components/views/auth/PassphraseField.tsx index 985cf7724d..6770b141a5 100644 --- a/src/components/views/auth/PassphraseField.tsx +++ b/src/components/views/auth/PassphraseField.tsx @@ -15,6 +15,7 @@ import withValidation, { IFieldState, IValidationResult } from "../elements/Vali import { _t, _td, TranslationKey } from "../../../languageHandler"; import Field, { IInputProps } from "../elements/Field"; import { MatrixClientPeg } from "../../../MatrixClientPeg"; +import { Alignment } from "../elements/Tooltip"; interface IProps extends Omit<IInputProps, "onValidate" | "element"> { autoFocus?: boolean; @@ -30,6 +31,7 @@ interface IProps extends Omit<IInputProps, "onValidate" | "element"> { labelEnterPassword: TranslationKey; labelStrongPassword: TranslationKey; labelAllowedButUnsafe: TranslationKey; + tooltipAlignment?: Alignment; onChange(ev: React.FormEvent<HTMLElement>): void; onValidate?(result: IValidationResult): void; @@ -111,6 +113,7 @@ class PassphraseField extends PureComponent<IProps> { value={this.props.value} onChange={this.props.onChange} onValidate={this.onValidate} + tooltipAlignment={this.props.tooltipAlignment} /> ); } diff --git a/src/components/views/auth/RegistrationForm.tsx b/src/components/views/auth/RegistrationForm.tsx index c8f7fd3d0f..4df3313758 100644 --- a/src/components/views/auth/RegistrationForm.tsx +++ b/src/components/views/auth/RegistrationForm.tsx @@ -26,6 +26,7 @@ import RegistrationEmailPromptDialog from "../dialogs/RegistrationEmailPromptDia import CountryDropdown from "./CountryDropdown"; import PassphraseConfirmField from "./PassphraseConfirmField"; import { PosthogAnalytics } from "../../../PosthogAnalytics"; +import { Alignment } from "../elements/Tooltip"; enum RegistrationField { Email = "field_email", @@ -58,6 +59,7 @@ interface IProps { serverConfig: ValidatedServerConfig; canSubmit?: boolean; matrixClient: MatrixClient; + mobileRegister?: boolean; onRegisterClick(params: { username: string; @@ -439,6 +441,13 @@ export default class RegistrationForm extends React.PureComponent<IProps, IState return true; } + private tooltipAlignment(): Alignment | undefined { + if (this.props.mobileRegister) { + return Alignment.Bottom; + } + return undefined; + } + private renderEmail(): ReactNode { if (!this.showEmail()) { return null; @@ -454,6 +463,7 @@ export default class RegistrationForm extends React.PureComponent<IProps, IState validationRules={this.validateEmailRules.bind(this)} onChange={this.onEmailChange} onValidate={this.onEmailValidate} + tooltipAlignment={this.tooltipAlignment()} /> ); } @@ -468,6 +478,7 @@ export default class RegistrationForm extends React.PureComponent<IProps, IState onChange={this.onPasswordChange} onValidate={this.onPasswordValidate} userInputs={[this.state.username]} + tooltipAlignment={this.tooltipAlignment()} /> ); } @@ -482,6 +493,7 @@ export default class RegistrationForm extends React.PureComponent<IProps, IState password={this.state.password} onChange={this.onPasswordConfirmChange} onValidate={this.onPasswordConfirmValidate} + tooltipAlignment={this.tooltipAlignment()} /> ); } @@ -526,6 +538,9 @@ export default class RegistrationForm extends React.PureComponent<IProps, IState value={this.state.username} onChange={this.onUsernameChange} onValidate={this.onUsernameValidate} + tooltipAlignment={this.tooltipAlignment()} + autoCorrect="off" + autoCapitalize="none" /> ); } @@ -557,14 +572,28 @@ export default class RegistrationForm extends React.PureComponent<IProps, IState } } + let passwordFields: JSX.Element | undefined; + if (this.props.mobileRegister) { + passwordFields = ( + <> + <div className="mx_AuthBody_fieldRow">{this.renderPassword()}</div> + <div className="mx_AuthBody_fieldRow">{this.renderPasswordConfirm()}</div> + </> + ); + } else { + passwordFields = ( + <div className="mx_AuthBody_fieldRow"> + {this.renderPassword()} + {this.renderPasswordConfirm()} + </div> + ); + } + return ( <div> <form onSubmit={this.onSubmit}> <div className="mx_AuthBody_fieldRow">{this.renderUsername()}</div> - <div className="mx_AuthBody_fieldRow"> - {this.renderPassword()} - {this.renderPasswordConfirm()} - </div> + {passwordFields} <div className="mx_AuthBody_fieldRow"> {this.renderEmail()} {this.renderPhoneNumber()} diff --git a/src/components/views/elements/Field.tsx b/src/components/views/elements/Field.tsx index 4326f63cd7..6cc5dffc40 100644 --- a/src/components/views/elements/Field.tsx +++ b/src/components/views/elements/Field.tsx @@ -17,7 +17,7 @@ import classNames from "classnames"; import { debounce } from "lodash"; import { IFieldState, IValidationResult } from "./Validation"; -import Tooltip from "./Tooltip"; +import Tooltip, { Alignment } from "./Tooltip"; import { Key } from "../../../Keyboard"; // Invoke validation from user input (when typing, etc.) at most once every N ms. @@ -60,6 +60,8 @@ interface IProps { tooltipContent?: React.ReactNode; // If specified the tooltip will be shown regardless of feedback forceTooltipVisible?: boolean; + // If specified, the tooltip with be aligned accorindly with the field, defaults to Right. + tooltipAlignment?: Alignment; // If specified alongside tooltipContent, the class name to apply to the // tooltip itself. tooltipClassName?: string; @@ -261,6 +263,7 @@ export default class Field extends React.PureComponent<PropShapes, IState> { validateOnFocus, usePlaceholderAsHint, forceTooltipVisible, + tooltipAlignment, ...inputProps } = this.props; @@ -286,7 +289,7 @@ export default class Field extends React.PureComponent<PropShapes, IState> { tooltipClassName={classNames("mx_Field_tooltip", "mx_Tooltip_noMargin", tooltipClassName)} visible={visible} label={tooltipContent || this.state.feedback} - alignment={Tooltip.Alignment.Right} + alignment={tooltipAlignment || Alignment.Right} role={role} /> ); diff --git a/test/components/structures/MatrixChat-test.tsx b/test/components/structures/MatrixChat-test.tsx index bae633b159..1003d1d167 100644 --- a/test/components/structures/MatrixChat-test.tsx +++ b/test/components/structures/MatrixChat-test.tsx @@ -55,6 +55,7 @@ import { MatrixClientPeg as peg } from "../../../src/MatrixClientPeg"; import DMRoomMap from "../../../src/utils/DMRoomMap"; import { ReleaseAnnouncementStore } from "../../../src/stores/ReleaseAnnouncementStore"; import { DRAFT_LAST_CLEANUP_KEY } from "../../../src/DraftCleaner"; +import { UIFeature } from "../../../src/settings/UIFeature"; jest.mock("matrix-js-sdk/src/oidc/authorize", () => ({ completeAuthorizationCodeGrant: jest.fn(), @@ -1462,4 +1463,42 @@ describe("<MatrixChat />", () => { }); }); }); + + describe("mobile registration", () => { + const getComponentAndWaitForReady = async (): Promise<RenderResult> => { + const renderResult = getComponent(); + // wait for welcome page chrome render + await screen.findByText("powered by Matrix"); + + // go to mobile_register page + defaultDispatcher.dispatch({ + action: "start_mobile_registration", + }); + + await flushPromises(); + + return renderResult; + }; + + const enabledMobileRegistration = (): void => { + jest.spyOn(SettingsStore, "getValue").mockImplementation((settingName: string) => { + if (settingName === "Registration.mobileRegistrationHelper") return true; + if (settingName === UIFeature.Registration) return true; + }); + }; + + it("should render welcome screen if mobile registration is not enabled in settings", async () => { + await getComponentAndWaitForReady(); + + await screen.findByText("powered by Matrix"); + }); + + it("should render mobile registration", async () => { + enabledMobileRegistration(); + + await getComponentAndWaitForReady(); + + expect(screen.getByTestId("mobile-register")).toBeInTheDocument(); + }); + }); }); diff --git a/test/components/structures/auth/Registration-test.tsx b/test/components/structures/auth/Registration-test.tsx index c31eff9b7c..9a83f00a9d 100644 --- a/test/components/structures/auth/Registration-test.tsx +++ b/test/components/structures/auth/Registration-test.tsx @@ -8,7 +8,7 @@ Please see LICENSE files in the repository root for full details. */ import React from "react"; -import { fireEvent, render, screen, waitForElementToBeRemoved } from "@testing-library/react"; +import { fireEvent, render, screen, waitFor, waitForElementToBeRemoved } from "@testing-library/react"; import { createClient, MatrixClient, MatrixError, OidcClientConfig } from "matrix-js-sdk/src/matrix"; import { mocked, MockedObject } from "jest-mock"; import fetchMock from "fetch-mock-jest"; @@ -87,12 +87,23 @@ describe("Registration", function () { const defaultHsUrl = "https://matrix.org"; const defaultIsUrl = "https://vector.im"; - function getRawComponent(hsUrl = defaultHsUrl, isUrl = defaultIsUrl, authConfig?: OidcClientConfig) { - return <Registration {...defaultProps} serverConfig={mkServerConfig(hsUrl, isUrl, authConfig)} />; + function getRawComponent( + hsUrl = defaultHsUrl, + isUrl = defaultIsUrl, + authConfig?: OidcClientConfig, + mobileRegister?: boolean, + ) { + return ( + <Registration + {...defaultProps} + serverConfig={mkServerConfig(hsUrl, isUrl, authConfig)} + mobileRegister={mobileRegister} + /> + ); } - function getComponent(hsUrl?: string, isUrl?: string, authConfig?: OidcClientConfig) { - return render(getRawComponent(hsUrl, isUrl, authConfig)); + function getComponent(hsUrl?: string, isUrl?: string, authConfig?: OidcClientConfig, mobileRegister?: boolean) { + return render(getRawComponent(hsUrl, isUrl, authConfig, mobileRegister)); } it("should show server picker", async function () { @@ -208,5 +219,31 @@ describe("Registration", function () { ); }); }); + + describe("when is mobile registeration", () => { + it("should not show server picker", async function () { + const { container } = getComponent(defaultHsUrl, defaultIsUrl, undefined, true); + expect(container.querySelector(".mx_ServerPicker")).toBeFalsy(); + }); + + it("should show username field with autocaps disabled", async function () { + const { container } = getComponent(defaultHsUrl, defaultIsUrl, undefined, true); + + await waitFor(() => + expect(container.querySelector("#mx_RegistrationForm_username")).toHaveAttribute( + "autocapitalize", + "none", + ), + ); + }); + + it("should show password and confirm password fields in separate rows", async function () { + const { container } = getComponent(defaultHsUrl, defaultIsUrl, undefined, true); + + await waitFor(() => expect(container.querySelector("#mx_RegistrationForm_username")).toBeTruthy()); + // when password and confirm password fields are in separate rows there should be 4 rather than 3 + expect(container.querySelectorAll(".mx_AuthBody_fieldRow")).toHaveLength(4); + }); + }); }); }); From a248788ef9a5b659a46fab531f199a4752a90092 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Fri, 20 Sep 2024 11:41:56 +0000 Subject: [PATCH 16/21] Update peter-evans/create-pull-request digest to 5e91468 (#64) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- .github/workflows/playwright-image-updates.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/playwright-image-updates.yaml b/.github/workflows/playwright-image-updates.yaml index 99f7465396..4d4c08f566 100644 --- a/.github/workflows/playwright-image-updates.yaml +++ b/.github/workflows/playwright-image-updates.yaml @@ -20,7 +20,7 @@ jobs: - name: Create Pull Request id: cpr - uses: peter-evans/create-pull-request@4320041ed380b20e97d388d56a7fb4f9b8c20e79 # v7 + uses: peter-evans/create-pull-request@5e914681df9dc83aa4e4905692ca88beb2f9e91f # v7 with: token: ${{ secrets.ELEMENT_BOT_TOKEN }} branch: actions/playwright-image-updates From d56b9ed9bd7ac6dae6a89bcff661d23ce6abf687 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 23 Sep 2024 10:13:49 +0200 Subject: [PATCH 17/21] Update dependency eslint to v8.57.1 (#68) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- package.json | 2 +- yarn.lock | 38 +++++++++++++++++++------------------- 2 files changed, 20 insertions(+), 20 deletions(-) diff --git a/package.json b/package.json index 30a16036ff..1ac488e7dd 100644 --- a/package.json +++ b/package.json @@ -198,7 +198,7 @@ "axe-core": "4.10.0", "babel-jest": "^29.0.0", "blob-polyfill": "^9.0.0", - "eslint": "8.57.0", + "eslint": "8.57.1", "eslint-config-google": "^0.14.0", "eslint-config-prettier": "^9.0.0", "eslint-plugin-deprecate": "0.8.5", diff --git a/yarn.lock b/yarn.lock index 8209709b1a..304955409a 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1515,10 +1515,10 @@ minimatch "^3.1.2" strip-json-comments "^3.1.1" -"@eslint/js@8.57.0": - version "8.57.0" - resolved "https://registry.yarnpkg.com/@eslint/js/-/js-8.57.0.tgz#a5417ae8427873f1dd08b70b3574b453e67b5f7f" - integrity sha512-Ys+3g2TaW7gADOJzPt83SJtCDhMjndcDMFVQ/Tj9iA1BfJzFKD9mAUXT3OenpuPHbI6P/myECxRJrofUsDx/5g== +"@eslint/js@8.57.1": + version "8.57.1" + resolved "https://registry.yarnpkg.com/@eslint/js/-/js-8.57.1.tgz#de633db3ec2ef6a3c89e2f19038063e8a122e2c2" + integrity sha512-d9zaMRSTIKDLhctzH12MtXvJKSSUhaHcjV+2Z+GK+EEY7XKpP5yR4x+N3TAcHTcu963nIr+TMcCb4DBCYX1z6Q== "@floating-ui/core@^1.6.0": version "1.6.5" @@ -1556,12 +1556,12 @@ resolved "https://registry.yarnpkg.com/@floating-ui/utils/-/utils-0.2.5.tgz#105c37d9d9620ce69b7f692a20c821bf1ad2cbf9" integrity sha512-sTcG+QZ6fdEUObICavU+aB3Mp8HY4n14wYHdxK4fXjPmv3PXZZeY5RaguJmGyeH/CJQhX3fqKUtS4qc1LoHwhQ== -"@humanwhocodes/config-array@^0.11.14": - version "0.11.14" - resolved "https://registry.yarnpkg.com/@humanwhocodes/config-array/-/config-array-0.11.14.tgz#d78e481a039f7566ecc9660b4ea7fe6b1fec442b" - integrity sha512-3T8LkOmg45BV5FICb15QQMsyUSWrQ8AygVfC7ZG32zOalnqrilm018ZVCw0eapXux8FtA33q8PSRSstjee3jSg== +"@humanwhocodes/config-array@^0.13.0": + version "0.13.0" + resolved "https://registry.yarnpkg.com/@humanwhocodes/config-array/-/config-array-0.13.0.tgz#fb907624df3256d04b9aa2df50d7aa97ec648748" + integrity sha512-DZLEEqFWQFiyK6h5YIeynKx7JlvCYWL0cImfSRXZ9l4Sg2efkFGTuFf6vzXjK1cq6IYkU+Eg/JizXw+TD2vRNw== dependencies: - "@humanwhocodes/object-schema" "^2.0.2" + "@humanwhocodes/object-schema" "^2.0.3" debug "^4.3.1" minimatch "^3.0.5" @@ -1570,10 +1570,10 @@ resolved "https://registry.yarnpkg.com/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz#af5b2691a22b44be847b0ca81641c5fb6ad0172c" integrity sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA== -"@humanwhocodes/object-schema@^2.0.2": - version "2.0.2" - resolved "https://registry.yarnpkg.com/@humanwhocodes/object-schema/-/object-schema-2.0.2.tgz#d9fae00a2d5cb40f92cfe64b47ad749fbc38f917" - integrity sha512-6EwiSjwWYP7pTckG6I5eyFANjPhmPjUX9JRLUSfNPC7FX7zK9gyZAfUEaECL6ALTpGX5AjnBq3C9XmVWPitNpw== +"@humanwhocodes/object-schema@^2.0.3": + version "2.0.3" + resolved "https://registry.yarnpkg.com/@humanwhocodes/object-schema/-/object-schema-2.0.3.tgz#4a2868d75d6d6963e423bcf90b7fd1be343409d3" + integrity sha512-93zYdMES/c1D69yZiKDBj0V24vqNzB/koF26KPaagAfd3P/4gUlh3Dys5ogAK+Exi9QyzlD8x/08Zt7wIKcDcA== "@isaacs/cliui@^8.0.2": version "8.0.2" @@ -4857,16 +4857,16 @@ eslint-visitor-keys@^4.0.0: resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-4.0.0.tgz#e3adc021aa038a2a8e0b2f8b0ce8f66b9483b1fb" integrity sha512-OtIRv/2GyiF6o/d8K7MYKKbXrOUBIK6SfkIRM4Z0dY3w+LiQ0vy3F57m0Z71bjbyeiWFiHJ8brqnmE6H6/jEuw== -eslint@8.57.0: - version "8.57.0" - resolved "https://registry.yarnpkg.com/eslint/-/eslint-8.57.0.tgz#c786a6fd0e0b68941aaf624596fb987089195668" - integrity sha512-dZ6+mexnaTIbSBZWgou51U6OmzIhYM2VcNdtiTtI7qPNZm35Akpr0f6vtw3w1Kmn5PYo+tZVfh13WrhpS6oLqQ== +eslint@8.57.1: + version "8.57.1" + resolved "https://registry.yarnpkg.com/eslint/-/eslint-8.57.1.tgz#7df109654aba7e3bbe5c8eae533c5e461d3c6ca9" + integrity sha512-ypowyDxpVSYpkXr9WPv2PAZCtNip1Mv5KTW0SCurXv/9iOpcrH9PaqUElksqEB6pChqHGDRCFTyrZlGhnLNGiA== dependencies: "@eslint-community/eslint-utils" "^4.2.0" "@eslint-community/regexpp" "^4.6.1" "@eslint/eslintrc" "^2.1.4" - "@eslint/js" "8.57.0" - "@humanwhocodes/config-array" "^0.11.14" + "@eslint/js" "8.57.1" + "@humanwhocodes/config-array" "^0.13.0" "@humanwhocodes/module-importer" "^1.0.1" "@nodelib/fs.walk" "^1.2.8" "@ungap/structured-clone" "^1.2.0" From 9aa09d4b15694328ceca175d98600293ad760883 Mon Sep 17 00:00:00 2001 From: David Baker <dbkr@users.noreply.github.com> Date: Mon, 23 Sep 2024 09:29:24 +0100 Subject: [PATCH 18/21] Maybe fix flakey AddRemoveThreepid test (#81) I have no idea why this is flaking. There are warnings about things not being wrapped in act() which may be relevant... this makes the warnings happy, although apparently should not be necessary. https://github.com/testing-library/user-event/discussions/906 and https://github.com/testing-library/user-event/issues/497 are depressing reading (making the versions the same didn't help). I think my conclusion might be to do this until we're able to upgrade to the latest testing-library, then re-evaluate. It still may or may not fix the flake. --- .../settings/AddRemoveThreepids-test.tsx | 21 +++++++++++++------ 1 file changed, 15 insertions(+), 6 deletions(-) diff --git a/test/components/views/settings/AddRemoveThreepids-test.tsx b/test/components/views/settings/AddRemoveThreepids-test.tsx index ec56d9f03b..9cdfe4ec18 100644 --- a/test/components/views/settings/AddRemoveThreepids-test.tsx +++ b/test/components/views/settings/AddRemoveThreepids-test.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 { render, screen } from "@testing-library/react"; +import { render, screen, waitFor } from "@testing-library/react"; import { MatrixClient, ThreepidMedium } from "matrix-js-sdk/src/matrix"; import React from "react"; import userEvent from "@testing-library/user-event"; @@ -218,7 +218,17 @@ describe("AddRemoveThreepids", () => { await userEvent.type(input, PHONE1_LOCALNUM); const addButton = screen.getByRole("button", { name: "Add" }); - await userEvent.click(addButton); + userEvent.click(addButton); + + const continueButton = await screen.findByRole("button", { name: "Continue" }); + + await expect(continueButton).toHaveAttribute("aria-disabled", "true"); + + await expect( + await screen.findByText( + `A text message has been sent to +${PHONE1.address}. Please enter the verification code it contains.`, + ), + ).toBeInTheDocument(); expect(client.requestAdd3pidMsisdnToken).toHaveBeenCalledWith( "GB", @@ -226,15 +236,14 @@ describe("AddRemoveThreepids", () => { client.generateClientSecret(), 1, ); - const continueButton = screen.getByRole("button", { name: "Continue" }); - - expect(continueButton).toHaveAttribute("aria-disabled", "true"); const verificationInput = screen.getByRole("textbox", { name: "Verification code" }); await userEvent.type(verificationInput, "123456"); expect(continueButton).not.toHaveAttribute("aria-disabled", "true"); - await userEvent.click(continueButton); + userEvent.click(continueButton); + + await waitFor(() => expect(continueButton).toHaveAttribute("aria-disabled", "true")); expect(client.addThreePidOnly).toHaveBeenCalledWith({ client_secret: client.generateClientSecret(), From 47a9377d63d5c92081143deda2eb9827c216f9fa Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 23 Sep 2024 09:47:09 +0000 Subject: [PATCH 19/21] Update dependency @types/react to v17.0.82 (#66) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- package.json | 4 ++-- yarn.lock | 8 ++++---- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/package.json b/package.json index 1ac488e7dd..35718c7713 100644 --- a/package.json +++ b/package.json @@ -62,7 +62,7 @@ }, "resolutions": { "@types/react-dom": "17.0.25", - "@types/react": "17.0.80", + "@types/react": "17.0.82", "@types/seedrandom": "3.0.8", "oidc-client-ts": "3.0.1", "jwt-decode": "4.0.0", @@ -183,7 +183,7 @@ "@types/node-fetch": "^2.6.2", "@types/pako": "^2.0.0", "@types/qrcode": "^1.3.5", - "@types/react": "17.0.80", + "@types/react": "17.0.82", "@types/react-beautiful-dnd": "^13.0.0", "@types/react-dom": "17.0.25", "@types/react-transition-group": "^4.4.0", diff --git a/yarn.lock b/yarn.lock index 304955409a..a52ffad8f5 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2858,10 +2858,10 @@ dependencies: "@types/react" "*" -"@types/react@*", "@types/react@17.0.80", "@types/react@^17": - version "17.0.80" - resolved "https://registry.yarnpkg.com/@types/react/-/react-17.0.80.tgz#a5dfc351d6a41257eb592d73d3a85d3b7dbcbb41" - integrity sha512-LrgHIu2lEtIo8M7d1FcI3BdwXWoRQwMoXOZ7+dPTW0lYREjmlHl3P0U1VD0i/9tppOuv8/sam7sOjx34TxSFbA== +"@types/react@*", "@types/react@17.0.82", "@types/react@^17": + version "17.0.82" + resolved "https://registry.yarnpkg.com/@types/react/-/react-17.0.82.tgz#eb84c38ee1023cd61be1b909fde083ac83fc163f" + integrity sha512-wTW8Lu/PARGPFE8tOZqCvprOKg5sen/2uS03yKn2xbCDFP9oLncm7vMDQ2+dEQXHVIXrOpW6u72xUXEXO0ypSw== dependencies: "@types/prop-types" "*" "@types/scheduler" "^0.16" From ef1d4f6c12214aac69000a7d6174772ea36b157d Mon Sep 17 00:00:00 2001 From: Andrew Ferrazzutti <andrewf@element.io> Date: Mon, 23 Sep 2024 06:40:40 -0400 Subject: [PATCH 20/21] Grant Element Call widget capabilities for "raise hand" feature (#82) * Grant Element Call widget caps for "raise hand" This allows the widget to send and receive event types used by the "raise hand" feature (element-hq/element-call#2542) without prompting the user to grant the capabilities to do so. * Lint --- src/stores/widgets/StopGapWidgetDriver.ts | 2 +- test/stores/widgets/StopGapWidgetDriver-test.ts | 4 ++++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/src/stores/widgets/StopGapWidgetDriver.ts b/src/stores/widgets/StopGapWidgetDriver.ts index e5435f595e..88e79d97f2 100644 --- a/src/stores/widgets/StopGapWidgetDriver.ts +++ b/src/stores/widgets/StopGapWidgetDriver.ts @@ -175,7 +175,7 @@ export class StopGapWidgetDriver extends WidgetDriver { WidgetEventCapability.forStateEvent(EventDirection.Receive, EventType.RoomCreate).raw, ); - const sendRecvRoomEvents = ["io.element.call.encryption_keys"]; + const sendRecvRoomEvents = ["io.element.call.encryption_keys", EventType.Reaction, EventType.RoomRedaction]; for (const eventType of sendRecvRoomEvents) { this.allowedCapabilities.add(WidgetEventCapability.forRoomEvent(EventDirection.Send, eventType).raw); this.allowedCapabilities.add(WidgetEventCapability.forRoomEvent(EventDirection.Receive, eventType).raw); diff --git a/test/stores/widgets/StopGapWidgetDriver-test.ts b/test/stores/widgets/StopGapWidgetDriver-test.ts index 57752a67af..6e3387e216 100644 --- a/test/stores/widgets/StopGapWidgetDriver-test.ts +++ b/test/stores/widgets/StopGapWidgetDriver-test.ts @@ -94,6 +94,10 @@ describe("StopGapWidgetDriver", () => { "org.matrix.msc2762.timeline:!1:example.org", "org.matrix.msc2762.send.event:org.matrix.rageshake_request", "org.matrix.msc2762.receive.event:org.matrix.rageshake_request", + "org.matrix.msc2762.send.event:m.reaction", + "org.matrix.msc2762.receive.event:m.reaction", + "org.matrix.msc2762.send.event:m.room.redaction", + "org.matrix.msc2762.receive.event:m.room.redaction", "org.matrix.msc2762.receive.state_event:m.room.create", "org.matrix.msc2762.receive.state_event:m.room.member", "org.matrix.msc2762.receive.state_event:org.matrix.msc3401.call", From a1bdceed3e544a6dd1b5efa816611686a80c8014 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 23 Sep 2024 12:59:52 +0000 Subject: [PATCH 21/21] Update dependency @types/node to v18.19.50 (#65) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- yarn.lock | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/yarn.lock b/yarn.lock index a52ffad8f5..8adf98fa0b 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2784,9 +2784,9 @@ undici-types "~5.26.4" "@types/node@18": - version "18.19.48" - resolved "https://registry.yarnpkg.com/@types/node/-/node-18.19.48.tgz#3a1696f4a7298d8831ed9ce47db62bf4c62c8880" - integrity sha512-7WevbG4ekUcRQSZzOwxWgi5dZmTak7FaxXDoW7xVxPBmKx1rTzfmRLkeCgJzcbBnOV2dkhAPc8cCeT6agocpjg== + version "18.19.50" + resolved "https://registry.yarnpkg.com/@types/node/-/node-18.19.50.tgz#8652b34ee7c0e7e2004b3f08192281808d41bf5a" + integrity sha512-xonK+NRrMBRtkL1hVCc3G+uXtjh1Al4opBLjqVmipe5ZAaBYWW6cNAiBVZ1BvmkBhep698rP3UM3aRAdSALuhg== dependencies: undici-types "~5.26.4"