diff --git a/playwright/plugins/homeserver/synapse/index.ts b/playwright/plugins/homeserver/synapse/index.ts index 941a08d276..f789ca543b 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:b261d81d9a3615a7716fc92423ee5689b0b450ed49f87a4887e49ecab7aefe45"; +const DOCKER_TAG = "develop@sha256:489fe921e03440af87e001106c41c70ffc55a1e8078d1a7f45e16fbaddc5088a"; async function cfgDirFromTemplate(opts: StartHomeserverOpts): Promise> { const templateDir = path.join(__dirname, "templates", opts.template); diff --git a/src/MatrixClientPeg.ts b/src/MatrixClientPeg.ts index 9804ab5d82..ce87953118 100644 --- a/src/MatrixClientPeg.ts +++ b/src/MatrixClientPeg.ts @@ -35,13 +35,11 @@ import IdentityAuthClient from "./IdentityAuthClient"; import { crossSigningCallbacks } from "./SecurityManager"; import { SlidingSyncManager } from "./SlidingSyncManager"; import { _t, UserFriendlyError } from "./languageHandler"; -import { SettingLevel } from "./settings/SettingLevel"; import MatrixClientBackedController from "./settings/controllers/MatrixClientBackedController"; import ErrorDialog from "./components/views/dialogs/ErrorDialog"; import PlatformPeg from "./PlatformPeg"; import { formatList } from "./utils/FormattingUtils"; import SdkConfig from "./SdkConfig"; -import { Features } from "./settings/Settings"; import { setDeviceIsolationMode } from "./settings/controllers/DeviceIsolationModeController.ts"; export interface IMatrixClientCreds { @@ -333,11 +331,6 @@ class MatrixClientPegClass implements IMatrixClientPeg { logger.error("Warning! Not using an encryption key for rust crypto store."); } - // Record the fact that we used the Rust crypto stack with this client. This just guards against people - // rolling back to versions of EW that did not default to Rust crypto (which would lead to an error, since - // we cannot migrate from Rust to Legacy crypto). - await SettingsStore.setValue(Features.RustCrypto, null, SettingLevel.DEVICE, true); - await this.matrixClient.initRustCrypto({ storageKey: rustCryptoStoreKey, storagePassword: rustCryptoStorePassword, diff --git a/src/components/structures/RoomView.tsx b/src/components/structures/RoomView.tsx index aaf1db42ad..a128bf273a 100644 --- a/src/components/structures/RoomView.tsx +++ b/src/components/structures/RoomView.tsx @@ -671,6 +671,7 @@ export class RoomView extends React.Component { // the RoomView instance if (initial) { newState.room = this.context.client!.getRoom(newState.roomId) || undefined; + newState.isRoomEncrypted = null; if (newState.room) { newState.showApps = this.shouldShowApps(newState.room); this.onRoomLoaded(newState.room); @@ -713,6 +714,14 @@ export class RoomView extends React.Component { if (initial) { this.setupRoom(newState.room, newState.roomId, !!newState.joining, !!newState.shouldPeek); } + + // We don't block the initial setup but we want to make it early to not block the timeline rendering + const isRoomEncrypted = await this.getIsRoomEncrypted(newState.roomId); + this.setState({ + isRoomEncrypted, + ...(isRoomEncrypted && + newState.roomId && { e2eStatus: RoomView.e2eStatusCache.get(newState.roomId) ?? E2EStatus.Warning }), + }); }; private onConnectedCalls = (): void => { @@ -863,7 +872,7 @@ export class RoomView extends React.Component { return isManuallyShown && widgets.length > 0; } - public async componentDidMount(): Promise { + public componentDidMount(): void { this.unmounted = false; this.dispatcherRef = defaultDispatcher.register(this.onAction); @@ -1482,24 +1491,17 @@ export class RoomView extends React.Component { private async updateE2EStatus(room: Room): Promise { if (!this.context.client || !this.state.isRoomEncrypted) return; - - // If crypto is not currently enabled, we aren't tracking devices at all, - // so we don't know what the answer is. Let's error on the safe side and show - // a warning for this case. - let e2eStatus = RoomView.e2eStatusCache.get(room.roomId) ?? E2EStatus.Warning; - // set the state immediately then update, so we don't scare the user into thinking the room is unencrypted + const e2eStatus = await this.cacheAndGetE2EStatus(room, this.context.client); + if (this.unmounted) return; this.setState({ e2eStatus }); - - if (this.context.client.getCrypto()) { - /* At this point, the user has encryption on and cross-signing on */ - e2eStatus = await this.cacheAndGetE2EStatus(room, this.context.client); - if (this.unmounted) return; - this.setState({ e2eStatus }); - } } private async cacheAndGetE2EStatus(room: Room, client: MatrixClient): Promise { - const e2eStatus = await shieldStatusForRoom(client, room); + let e2eStatus = RoomView.e2eStatusCache.get(room.roomId); + // set the state immediately then update, so we don't scare the user into thinking the room is unencrypted + if (e2eStatus) this.setState({ e2eStatus }); + + e2eStatus = await shieldStatusForRoom(client, room); RoomView.e2eStatusCache.set(room.roomId, e2eStatus); return e2eStatus; } diff --git a/src/components/views/auth/LoginWithQR.tsx b/src/components/views/auth/LoginWithQR.tsx index e931b40a71..e18b0e24ab 100644 --- a/src/components/views/auth/LoginWithQR.tsx +++ b/src/components/views/auth/LoginWithQR.tsx @@ -108,12 +108,9 @@ export default class LoginWithQR extends React.Component { private generateAndShowCode = async (): Promise => { let rendezvous: MSC4108SignInWithQR; try { - const fallbackRzServer = this.props.client?.getClientWellKnown()?.["io.element.rendezvous"]?.server; - const transport = new MSC4108RendezvousSession({ onFailure: this.onFailure, client: this.props.client, - fallbackRzServer, }); await transport.send(""); const channel = new MSC4108SecureChannel(transport, undefined, this.onFailure); diff --git a/src/components/views/rooms/MessageComposerFormatBar.tsx b/src/components/views/rooms/MessageComposerFormatBar.tsx index 34798cc608..0ab359d9dd 100644 --- a/src/components/views/rooms/MessageComposerFormatBar.tsx +++ b/src/components/views/rooms/MessageComposerFormatBar.tsx @@ -33,6 +33,12 @@ interface IState { export default class MessageComposerFormatBar extends React.PureComponent { private readonly formatBarRef = createRef(); + /** + * The height of the format bar in pixels. + * Height 32px + 2px border + * @private + */ + private readonly BAR_HEIGHT = 34; public constructor(props: IProps) { super(props); @@ -96,7 +102,7 @@ export default class MessageComposerFormatBar extends React.PureComponent void; versions?: IServerVersions; - wellKnown?: IClientWellKnown; oidcClientConfig?: OidcClientConfig; isCrossSigningReady?: boolean; } @@ -35,10 +28,8 @@ export function shouldShowQr( isCrossSigningReady: boolean, oidcClientConfig?: OidcClientConfig, versions?: IServerVersions, - wellKnown?: IClientWellKnown, ): boolean { - const msc4108Supported = - !!versions?.unstable_features?.["org.matrix.msc4108"] || !!wellKnown?.["io.element.rendezvous"]?.server; + const msc4108Supported = !!versions?.unstable_features?.["org.matrix.msc4108"]; const deviceAuthorizationGrantSupported = oidcClientConfig?.metadata?.grant_types_supported.includes(DEVICE_CODE_SCOPE); @@ -51,15 +42,9 @@ export function shouldShowQr( ); } -const LoginWithQRSection: React.FC = ({ - onShowQr, - versions, - wellKnown, - oidcClientConfig, - isCrossSigningReady, -}) => { +const LoginWithQRSection: React.FC = ({ onShowQr, versions, oidcClientConfig, isCrossSigningReady }) => { const cli = useMatrixClientContext(); - const offerShowQr = shouldShowQr(cli, !!isCrossSigningReady, oidcClientConfig, versions, wellKnown); + const offerShowQr = shouldShowQr(cli, !!isCrossSigningReady, oidcClientConfig, versions); return ( diff --git a/src/components/views/settings/tabs/user/SessionManagerTab.tsx b/src/components/views/settings/tabs/user/SessionManagerTab.tsx index 2e16f45762..5e9445bb99 100644 --- a/src/components/views/settings/tabs/user/SessionManagerTab.tsx +++ b/src/components/views/settings/tabs/user/SessionManagerTab.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, { lazy, Suspense, useCallback, useContext, useEffect, useMemo, useRef, useState } from "react"; +import React, { lazy, Suspense, useCallback, useContext, useEffect, useRef, useState } from "react"; import { discoverAndValidateOIDCIssuerWellKnown, MatrixClient } from "matrix-js-sdk/src/matrix"; import { logger } from "matrix-js-sdk/src/logger"; import { defer } from "matrix-js-sdk/src/utils"; @@ -184,7 +184,6 @@ const SessionManagerTab: React.FC<{ const userId = matrixClient?.getUserId(); const currentUserMember = (userId && matrixClient?.getUser(userId)) || undefined; const clientVersions = useAsyncMemo(() => matrixClient.getVersions(), [matrixClient]); - const wellKnown = useMemo(() => matrixClient?.getClientWellKnown(), [matrixClient]); const oidcClientConfig = useAsyncMemo(async () => { try { const authIssuer = await matrixClient?.getAuthIssuer(); @@ -305,7 +304,6 @@ const SessionManagerTab: React.FC<{ diff --git a/src/settings/Settings.tsx b/src/settings/Settings.tsx index 1c27f03e88..08cff0c1bb 100644 --- a/src/settings/Settings.tsx +++ b/src/settings/Settings.tsx @@ -90,13 +90,6 @@ export enum Features { NotificationSettings2 = "feature_notification_settings2", OidcNativeFlow = "feature_oidc_native_flow", ReleaseAnnouncement = "feature_release_announcement", - - /** If true, use the Rust crypto implementation. - * - * This is no longer read, but we continue to populate it on all devices, to guard against people rolling back to - * old versions of EW that do not use rust crypto by default. - */ - RustCrypto = "feature_rust_crypto", } export const labGroupNames: Record = { @@ -469,10 +462,6 @@ export const SETTINGS: { [setting: string]: ISetting } = { description: _td("labs|oidc_native_flow_description"), default: false, }, - [Features.RustCrypto]: { - supportedLevels: LEVELS_DEVICE_ONLY_SETTINGS, - default: true, - }, /** * @deprecated in favor of {@link fontSizeDelta} */ diff --git a/src/vector/index.ts b/src/vector/index.ts index 60f0868eeb..42b69af70e 100644 --- a/src/vector/index.ts +++ b/src/vector/index.ts @@ -67,6 +67,10 @@ function checkBrowserFeatures(): boolean { // although this would start to make (more) assumptions about how rust-crypto loads its wasm. window.Modernizr.addTest("wasm", () => typeof WebAssembly === "object" && typeof WebAssembly.Module === "function"); + // Check that the session is in a secure context otherwise most Crypto & WebRTC APIs will be unavailable + // https://developer.mozilla.org/en-US/docs/Web/API/Window/isSecureContext + window.Modernizr.addTest("securecontext", () => window.isSecureContext); + const featureList = Object.keys(window.Modernizr) as Array; let featureComplete = true; diff --git a/test/unit-tests/MatrixClientPeg-test.ts b/test/unit-tests/MatrixClientPeg-test.ts index 5a19b568c0..4653340574 100644 --- a/test/unit-tests/MatrixClientPeg-test.ts +++ b/test/unit-tests/MatrixClientPeg-test.ts @@ -11,8 +11,6 @@ import fetchMockJest from "fetch-mock-jest"; import { advanceDateAndTime, stubClient } from "../test-utils"; import { IMatrixClientPeg, MatrixClientPeg as peg } from "../../src/MatrixClientPeg"; -import SettingsStore from "../../src/settings/SettingsStore"; -import { SettingLevel } from "../../src/settings/SettingLevel"; jest.useFakeTimers(); @@ -81,27 +79,18 @@ describe("MatrixClientPeg", () => { }); it("should initialise the rust crypto library by default", async () => { - const mockSetValue = jest.spyOn(SettingsStore, "setValue").mockResolvedValue(undefined); - const mockInitRustCrypto = jest.spyOn(testPeg.safeGet(), "initRustCrypto").mockResolvedValue(undefined); const cryptoStoreKey = new Uint8Array([1, 2, 3, 4]); await testPeg.start({ rustCryptoStoreKey: cryptoStoreKey }); expect(mockInitRustCrypto).toHaveBeenCalledWith({ storageKey: cryptoStoreKey }); - - // we should have stashed the setting in the settings store - expect(mockSetValue).toHaveBeenCalledWith("feature_rust_crypto", null, SettingLevel.DEVICE, true); }); it("Should migrate existing login", async () => { - const mockSetValue = jest.spyOn(SettingsStore, "setValue").mockResolvedValue(undefined); const mockInitRustCrypto = jest.spyOn(testPeg.safeGet(), "initRustCrypto").mockResolvedValue(undefined); await testPeg.start(); expect(mockInitRustCrypto).toHaveBeenCalledTimes(1); - - // we should have stashed the setting in the settings store - expect(mockSetValue).toHaveBeenCalledWith("feature_rust_crypto", null, SettingLevel.DEVICE, true); }); }); }); diff --git a/test/unit-tests/components/views/settings/devices/LoginWithQRSection-test.tsx b/test/unit-tests/components/views/settings/devices/LoginWithQRSection-test.tsx index dd6caef1ce..edaf7b39d1 100644 --- a/test/unit-tests/components/views/settings/devices/LoginWithQRSection-test.tsx +++ b/test/unit-tests/components/views/settings/devices/LoginWithQRSection-test.tsx @@ -56,7 +56,6 @@ describe("", () => { const defaultProps = { onShowQr: () => {}, versions: makeVersions({ "org.matrix.msc4108": true }), - wellKnown: {}, }; const getComponent = (props = {}) => ;