From d0afd65652bbfcc2888b73219310bb02794be8e5 Mon Sep 17 00:00:00 2001 From: thobyv-kismat Date: Sat, 21 Mar 2020 10:12:55 +0100 Subject: [PATCH 01/37] fix view community link icon contrast Signed-off-by: thobyv-kismat --- res/css/structures/_TagPanel.scss | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/res/css/structures/_TagPanel.scss b/res/css/structures/_TagPanel.scss index 472831c0d9..c1c5d92d3c 100644 --- a/res/css/structures/_TagPanel.scss +++ b/res/css/structures/_TagPanel.scss @@ -137,7 +137,7 @@ limitations under the License. top: -8px; border-radius: 8px; background-color: $neutral-badge-color; - color: #ffffff; + color: #000; font-weight: 600; font-size: 10px; text-align: center; From c41b39488b46ac772d3b0c0ba5c9c3b060e495e6 Mon Sep 17 00:00:00 2001 From: Michael Telatynski <7t3chguy@gmail.com> Date: Wed, 25 Mar 2020 23:35:36 +0000 Subject: [PATCH 02/37] Automatically redirect to SSO when the user clicks through to Login Signed-off-by: Michael Telatynski <7t3chguy@gmail.com> --- src/components/structures/auth/Login.js | 25 ++++++++++++++++++------- 1 file changed, 18 insertions(+), 7 deletions(-) diff --git a/src/components/structures/auth/Login.js b/src/components/structures/auth/Login.js index bfabc34a62..36df08627e 100644 --- a/src/components/structures/auth/Login.js +++ b/src/components/structures/auth/Login.js @@ -53,6 +53,10 @@ _td("Invalid base_url for m.identity_server"); _td("Identity server URL does not appear to be a valid identity server"); _td("General failure"); +const M_LOGIN_CAS = "m.login.cas"; +const M_LOGIN_SSO = "m.login.sso"; +const SSO_FLOWS = [M_LOGIN_SSO, M_LOGIN_CAS]; + /** * A wire component which glues together login UI components and Login logic */ @@ -122,11 +126,11 @@ export default createReactClass({ 'm.login.password': this._renderPasswordStep, // CAS and SSO are the same thing, modulo the url we link to - 'm.login.cas': () => this._renderSsoStep("cas"), - 'm.login.sso': () => this._renderSsoStep("sso"), + [M_LOGIN_CAS]: () => this._renderSsoStep("cas"), + [M_LOGIN_SSO]: () => this._renderSsoStep("sso"), }; - this._initLoginLogic(); + this._initLoginLogic(true); }, componentWillUnmount: function() { @@ -138,7 +142,7 @@ export default createReactClass({ newProps.serverConfig.isUrl === this.props.serverConfig.isUrl) return; // Ensure that we end up actually logging in to the right place - this._initLoginLogic(newProps.serverConfig.hsUrl, newProps.serverConfig.isUrl); + this._initLoginLogic(false, newProps.serverConfig.hsUrl, newProps.serverConfig.isUrl); }, onPasswordLoginError: function(errorText) { @@ -342,12 +346,12 @@ export default createReactClass({ onTryRegisterClick: function(ev) { const step = this._getCurrentFlowStep(); - if (step === 'm.login.sso' || step === 'm.login.cas') { + if (SSO_FLOWS.includes(step)) { // If we're showing SSO it means that registration is also probably disabled, // so intercept the click and instead pretend the user clicked 'Sign in with SSO'. ev.preventDefault(); ev.stopPropagation(); - const ssoKind = step === 'm.login.sso' ? 'sso' : 'cas'; + const ssoKind = step === M_LOGIN_SSO ? 'sso' : 'cas'; PlatformPeg.get().startSingleSignOn(this._loginLogic.createTemporaryClient(), ssoKind); } else { // Don't intercept - just go through to the register page @@ -369,7 +373,7 @@ export default createReactClass({ }); }, - _initLoginLogic: async function(hsUrl, isUrl) { + _initLoginLogic: async function(initial, hsUrl, isUrl) { hsUrl = hsUrl || this.props.serverConfig.hsUrl; isUrl = isUrl || this.props.serverConfig.isUrl; @@ -429,6 +433,13 @@ export default createReactClass({ continue; } + // if this is the initial render and the flow we choose is SSO/CAS then go to it automatically + // we do not do this when the user has changed to the server manually as that may be jarring. + if (initial && SSO_FLOWS.includes(flows[i].type)) { + const tmpCli = this._loginLogic.createTemporaryClient(); + PlatformPeg.get().startSingleSignOn(tmpCli, flows[i].type === M_LOGIN_SSO ? "sso": "cas"); + } + // we just pick the first flow where we support all the // steps. (we don't have a UI for multiple logins so let's skip // that for now). From a1c83a4f0e56316bdcb3d98cc70f8346e26abb4a Mon Sep 17 00:00:00 2001 From: RiotRobot Date: Thu, 26 Mar 2020 13:02:54 +0000 Subject: [PATCH 03/37] Upgrade matrix-js-sdk to 5.2.0-rc.1 --- package.json | 2 +- yarn.lock | 7 ++++--- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/package.json b/package.json index 1ff0fb6f55..29e4809e49 100644 --- a/package.json +++ b/package.json @@ -79,7 +79,7 @@ "is-ip": "^2.0.0", "linkifyjs": "^2.1.6", "lodash": "^4.17.14", - "matrix-js-sdk": "github:matrix-org/matrix-js-sdk#develop", + "matrix-js-sdk": "5.2.0-rc.1", "minimist": "^1.2.0", "pako": "^1.0.5", "png-chunks-extract": "^1.0.0", diff --git a/yarn.lock b/yarn.lock index 582d89137e..04dcab02ed 100644 --- a/yarn.lock +++ b/yarn.lock @@ -5689,9 +5689,10 @@ mathml-tag-names@^2.0.1: resolved "https://registry.yarnpkg.com/mathml-tag-names/-/mathml-tag-names-2.1.3.tgz#4ddadd67308e780cf16a47685878ee27b736a0a3" integrity sha512-APMBEanjybaPzUrfqU0IMU5I0AswKMH7k8OTLs0vvV4KZpExkTkY87nR/zpbuTPj+gARop7aGUbl11pnDfW6xg== -"matrix-js-sdk@github:matrix-org/matrix-js-sdk#develop": - version "5.1.1" - resolved "https://codeload.github.com/matrix-org/matrix-js-sdk/tar.gz/b2e154377a4268441a3b27b183dd7f7018187035" +matrix-js-sdk@5.2.0-rc.1: + version "5.2.0-rc.1" + resolved "https://registry.yarnpkg.com/matrix-js-sdk/-/matrix-js-sdk-5.2.0-rc.1.tgz#014239eb713ea3b648b7a573785d01edff1efd03" + integrity sha512-Jv/0kyZEtkfrD6mlq3g2YoFI2+eOBFOz5D186jJAvFg1W7UaQ5gn6iualR+2AKa1AIk2AT6lDcgPb1djZ7/3Vw== dependencies: "@babel/runtime" "^7.8.3" another-json "^0.2.0" From 91f706260b9f90984646555d2d444937765053c6 Mon Sep 17 00:00:00 2001 From: RiotRobot Date: Thu, 26 Mar 2020 13:21:10 +0000 Subject: [PATCH 04/37] Prepare changelog for v2.3.0-rc.1 --- CHANGELOG.md | 150 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 150 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 07e478fa02..378ba6f1d1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,153 @@ +Changes in [2.3.0-rc.1](https://github.com/matrix-org/matrix-react-sdk/releases/tag/v2.3.0-rc.1) (2020-03-26) +============================================================================================================= +[Full Changelog](https://github.com/matrix-org/matrix-react-sdk/compare/v2.2.3...v2.3.0-rc.1) + + * Upgrade JS SDK to 5.2.0-rc.1 + * Add a flag to control whether cross-signing signatures are trusted + [\#4277](https://github.com/matrix-org/matrix-react-sdk/pull/4277) + * Update from Weblate + [\#4282](https://github.com/matrix-org/matrix-react-sdk/pull/4282) + * Update copy on SSSS symmetric upgrade toast + [\#4281](https://github.com/matrix-org/matrix-react-sdk/pull/4281) + * Wait for SSSS upgrade to complete + [\#4270](https://github.com/matrix-org/matrix-react-sdk/pull/4270) + * Update cross-signing verification copy and fix i18n + [\#4278](https://github.com/matrix-org/matrix-react-sdk/pull/4278) + * Fix soft-crash on bad permalinks + [\#4280](https://github.com/matrix-org/matrix-react-sdk/pull/4280) + * Fix: make self-verification wait for incoming request + [\#4267](https://github.com/matrix-org/matrix-react-sdk/pull/4267) + * Fall back to non-standard persisted api for Safari + [\#4272](https://github.com/matrix-org/matrix-react-sdk/pull/4272) + * Respond to backup key sharing requests + [\#4275](https://github.com/matrix-org/matrix-react-sdk/pull/4275) + * Log and display secret sharing cache state + [\#4268](https://github.com/matrix-org/matrix-react-sdk/pull/4268) + * Support sending config and ready events to capable widgets (Jitsi) + [\#4266](https://github.com/matrix-org/matrix-react-sdk/pull/4266) + * If cached keys are present in the key backup dialog, use them + [\#4273](https://github.com/matrix-org/matrix-react-sdk/pull/4273) + * Fix formatbar not hidden on highlighted message sent + [\#4265](https://github.com/matrix-org/matrix-react-sdk/pull/4265) + * Support Jitsi conferences sent/received on Riot Mobile and older Riot Webs + [\#4252](https://github.com/matrix-org/matrix-react-sdk/pull/4252) + * Use unified function to check cross-signing is ready + [\#4263](https://github.com/matrix-org/matrix-react-sdk/pull/4263) + * Migrate SSSS to symmetric + [\#4224](https://github.com/matrix-org/matrix-react-sdk/pull/4224) + * Migration to symmetric SSSS + [\#4242](https://github.com/matrix-org/matrix-react-sdk/pull/4242) + * Always display verification request toasts on top + [\#4262](https://github.com/matrix-org/matrix-react-sdk/pull/4262) + * Fix: assume SAS is supported when starting request with .start + [\#4249](https://github.com/matrix-org/matrix-react-sdk/pull/4249) + * Fix logout when Olm failed to load. + [\#4261](https://github.com/matrix-org/matrix-react-sdk/pull/4261) + * Improve naming of Jitsi conferences + [\#4251](https://github.com/matrix-org/matrix-react-sdk/pull/4251) + * Handle matrix.to user permalink in-room rather than solo + [\#4245](https://github.com/matrix-org/matrix-react-sdk/pull/4245) + * Fix: filter room list (again) by canonical and alternative aliases + [\#4260](https://github.com/matrix-org/matrix-react-sdk/pull/4260) + * EventIndex: Add some logging to the file panel populating. + [\#4250](https://github.com/matrix-org/matrix-react-sdk/pull/4250) + * Update from Weblate + [\#4259](https://github.com/matrix-org/matrix-react-sdk/pull/4259) + * Migrate RoomView to React Contexts in the hope for better temporal stability + [\#4258](https://github.com/matrix-org/matrix-react-sdk/pull/4258) + * Update WidgetUtils.js fix Jitsi path + [\#4256](https://github.com/matrix-org/matrix-react-sdk/pull/4256) + * Fix local jitsi build url fail and missing argument + [\#4255](https://github.com/matrix-org/matrix-react-sdk/pull/4255) + * Add shortcut CmdOrCtrl+. to toggle right panel + [\#4244](https://github.com/matrix-org/matrix-react-sdk/pull/4244) + * Improve Keyboard Shortcuts. Add alt-arrows & alt-shift-arrows + [\#4241](https://github.com/matrix-org/matrix-react-sdk/pull/4241) + * Bring back legacy verification by comparing public device keys + [\#4240](https://github.com/matrix-org/matrix-react-sdk/pull/4240) + * Searching: Return an empty result if the search term is an empty string. + [\#4248](https://github.com/matrix-org/matrix-react-sdk/pull/4248) + * Break continuation on showHiddenEvents-rendered events + [\#4247](https://github.com/matrix-org/matrix-react-sdk/pull/4247) + * Watch for show-RR settings changes, use room-specific and fix margins + [\#4246](https://github.com/matrix-org/matrix-react-sdk/pull/4246) + * Register Mac electron specific Cmd+, shortcut to User Settings + [\#4243](https://github.com/matrix-org/matrix-react-sdk/pull/4243) + * Use a local wrapper for Jitsi calls + [\#4234](https://github.com/matrix-org/matrix-react-sdk/pull/4234) + * Invite Dialog fixes + [\#4233](https://github.com/matrix-org/matrix-react-sdk/pull/4233) + * RoomPreviewBar word-break the sender name too + [\#4239](https://github.com/matrix-org/matrix-react-sdk/pull/4239) + * Report to the user when a key signature upload fails + [\#4229](https://github.com/matrix-org/matrix-react-sdk/pull/4229) + * pre-send megolm keys when possible when a user starts typing + [\#4235](https://github.com/matrix-org/matrix-react-sdk/pull/4235) + * we don't do mx_fadable anymore so get rid of broken RightPanel disabling + [\#4238](https://github.com/matrix-org/matrix-react-sdk/pull/4238) + * Fix left left panel overflowing vertically + [\#4237](https://github.com/matrix-org/matrix-react-sdk/pull/4237) + * Fix custom tags causing left panel to over-expand + [\#4236](https://github.com/matrix-org/matrix-react-sdk/pull/4236) + * Add Keyboard shortcuts dialog + [\#4231](https://github.com/matrix-org/matrix-react-sdk/pull/4231) + * Don't use buildkite agent to upload logs + [\#4232](https://github.com/matrix-org/matrix-react-sdk/pull/4232) + * Remove Gemini Scrollbars + [\#4217](https://github.com/matrix-org/matrix-react-sdk/pull/4217) + * Room Directory Explore Servers redesign + [\#4209](https://github.com/matrix-org/matrix-react-sdk/pull/4209) + * Fix redo keyboard shortcut on macOS + [\#4110](https://github.com/matrix-org/matrix-react-sdk/pull/4110) + * Fix: ensure local state for aliases doesn't get garbled up + [\#4230](https://github.com/matrix-org/matrix-react-sdk/pull/4230) + * Rename 'jump to bottom' to avoid ublock block + [\#4208](https://github.com/matrix-org/matrix-react-sdk/pull/4208) + * Restore key backup in background after complete security + [\#4225](https://github.com/matrix-org/matrix-react-sdk/pull/4225) + * Fix key backup trust text for cross-signing + [\#4223](https://github.com/matrix-org/matrix-react-sdk/pull/4223) + * Add default on config setting to control call button in composer + [\#4227](https://github.com/matrix-org/matrix-react-sdk/pull/4227) + * Fix: make alternative addresses UX less confusing + [\#4221](https://github.com/matrix-org/matrix-react-sdk/pull/4221) + * Wait for verification request on login + [\#4222](https://github.com/matrix-org/matrix-react-sdk/pull/4222) + * EventIndex: Add support to delete events from the index. + [\#4204](https://github.com/matrix-org/matrix-react-sdk/pull/4204) + * EventIndex: Remove a checkpoint if the HTTP request returns a 403. + [\#4214](https://github.com/matrix-org/matrix-react-sdk/pull/4214) + * Move to composer when typing letters with Shift held + [\#4216](https://github.com/matrix-org/matrix-react-sdk/pull/4216) + * Wrap large room names when previewing them + [\#4213](https://github.com/matrix-org/matrix-react-sdk/pull/4213) + * Rename Review Devices to Review Sessions + [\#4219](https://github.com/matrix-org/matrix-react-sdk/pull/4219) + * Fix typo in tabIndex to make React happy + [\#4215](https://github.com/matrix-org/matrix-react-sdk/pull/4215) + * Proof of concept for custom theme adding + [\#4148](https://github.com/matrix-org/matrix-react-sdk/pull/4148) + * Remove stuff that yarn install doesn't think we need + [\#4205](https://github.com/matrix-org/matrix-react-sdk/pull/4205) + * Declare jsx in tsconfig for IDEs + [\#4207](https://github.com/matrix-org/matrix-react-sdk/pull/4207) + * Fix: best-effort to join room without canonical alias over federation from + room directory + [\#4210](https://github.com/matrix-org/matrix-react-sdk/pull/4210) + * Test for cross-signing homeserver support during login, toasts + [\#4206](https://github.com/matrix-org/matrix-react-sdk/pull/4206) + * Send verification request to a single device in a way compatible with non- + cross-signing + [\#4202](https://github.com/matrix-org/matrix-react-sdk/pull/4202) + * Fixes for removing local alias + [\#4199](https://github.com/matrix-org/matrix-react-sdk/pull/4199) + * yarn upgrade + [\#4201](https://github.com/matrix-org/matrix-react-sdk/pull/4201) + * Support TypeScript for React components + [\#4203](https://github.com/matrix-org/matrix-react-sdk/pull/4203) + * When room name is changed, show both the old and new name + [\#4183](https://github.com/matrix-org/matrix-react-sdk/pull/4183) + Changes in [2.2.3](https://github.com/matrix-org/matrix-react-sdk/releases/tag/v2.2.3) (2020-03-17) =================================================================================================== [Full Changelog](https://github.com/matrix-org/matrix-react-sdk/compare/v2.2.3-rc.1...v2.2.3) From 2fe0edd3eb7202fb352fa1f12ef9f12a0ce72ee0 Mon Sep 17 00:00:00 2001 From: RiotRobot Date: Thu, 26 Mar 2020 13:21:11 +0000 Subject: [PATCH 05/37] v2.3.0-rc.1 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 29e4809e49..7579cab714 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "matrix-react-sdk", - "version": "2.2.3", + "version": "2.3.0-rc.1", "description": "SDK for matrix.org using React", "author": "matrix.org", "repository": { From 7fbfd73e11e03a192d2bb74e3146b9ea07189e5d Mon Sep 17 00:00:00 2001 From: Michael Telatynski <7t3chguy@gmail.com> Date: Fri, 27 Mar 2020 01:17:42 +0000 Subject: [PATCH 06/37] Show modal on "instant SSO" Signed-off-by: Michael Telatynski <7t3chguy@gmail.com> --- src/BasePlatform.js | 19 ++++++++++++++++++- src/components/structures/auth/Login.js | 2 +- 2 files changed, 19 insertions(+), 2 deletions(-) diff --git a/src/BasePlatform.js b/src/BasePlatform.js index 5d809eb28f..489d9474a1 100644 --- a/src/BasePlatform.js +++ b/src/BasePlatform.js @@ -22,6 +22,11 @@ limitations under the License. import {MatrixClient} from "matrix-js-sdk"; import dis from './dispatcher'; import BaseEventIndexManager from './indexing/BaseEventIndexManager'; +import Modal from "./Modal"; +import InfoDialog from "./components/views/dialogs/InfoDialog"; +import {_t} from "./languageHandler"; +import Spinner from "./components/views/elements/Spinner"; +import React from "react"; /** * Base class for classes that provide platform-specific functionality @@ -183,9 +188,21 @@ export default class BasePlatform { * Begin Single Sign On flows. * @param {MatrixClient} mxClient the matrix client using which we should start the flow * @param {"sso"|"cas"} loginType the type of SSO it is, CAS/SSO. + * @param {boolean} showModal whether or not to show the spinner modal. */ - startSingleSignOn(mxClient: MatrixClient, loginType: "sso"|"cas") { + startSingleSignOn(mxClient: MatrixClient, loginType: "sso"|"cas", showModal: boolean) { const callbackUrl = this.getSSOCallbackUrl(mxClient.getHomeserverUrl(), mxClient.getIdentityServerUrl()); + if (showModal) { + Modal.createTrackedDialog('BasePlatform', 'SSO', InfoDialog, { + title: _t("Single sign-on"), + description: , + }); + } window.location.href = mxClient.getSsoLoginUrl(callbackUrl.toString(), loginType); // redirect to SSO } } diff --git a/src/components/structures/auth/Login.js b/src/components/structures/auth/Login.js index 36df08627e..6c6a8bedbd 100644 --- a/src/components/structures/auth/Login.js +++ b/src/components/structures/auth/Login.js @@ -437,7 +437,7 @@ export default createReactClass({ // we do not do this when the user has changed to the server manually as that may be jarring. if (initial && SSO_FLOWS.includes(flows[i].type)) { const tmpCli = this._loginLogic.createTemporaryClient(); - PlatformPeg.get().startSingleSignOn(tmpCli, flows[i].type === M_LOGIN_SSO ? "sso": "cas"); + PlatformPeg.get().startSingleSignOn(tmpCli, flows[i].type === M_LOGIN_SSO ? "sso": "cas", true); } // we just pick the first flow where we support all the From 98f9f1e956235c290586f95e9b10fcfe2231c487 Mon Sep 17 00:00:00 2001 From: Michael Telatynski <7t3chguy@gmail.com> Date: Fri, 27 Mar 2020 09:59:43 +0000 Subject: [PATCH 07/37] i18n Signed-off-by: Michael Telatynski <7t3chguy@gmail.com> --- src/i18n/strings/en_EN.json | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/i18n/strings/en_EN.json b/src/i18n/strings/en_EN.json index 12bd462937..4677f40ce1 100644 --- a/src/i18n/strings/en_EN.json +++ b/src/i18n/strings/en_EN.json @@ -25,6 +25,8 @@ "Error": "Error", "Unable to load! Check your network connectivity and try again.": "Unable to load! Check your network connectivity and try again.", "Dismiss": "Dismiss", + "Single sign-on": "Single sign-on", + "Click here if you're not redirected automatically": "Click here if you're not redirected automatically", "Call Failed": "Call Failed", "There are unknown sessions in this room: if you proceed without verifying them, it will be possible for someone to eavesdrop on your call.": "There are unknown sessions in this room: if you proceed without verifying them, it will be possible for someone to eavesdrop on your call.", "Review Sessions": "Review Sessions", From 548e9184372d9a7c8a74a07841f97134ee55fbb4 Mon Sep 17 00:00:00 2001 From: Michael Telatynski <7t3chguy@gmail.com> Date: Fri, 27 Mar 2020 12:01:10 +0000 Subject: [PATCH 08/37] only auto-sso when disable_custom_urls is true Signed-off-by: Michael Telatynski <7t3chguy@gmail.com> --- src/components/structures/auth/Login.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/components/structures/auth/Login.js b/src/components/structures/auth/Login.js index 6c6a8bedbd..134f6fa6f3 100644 --- a/src/components/structures/auth/Login.js +++ b/src/components/structures/auth/Login.js @@ -435,7 +435,8 @@ export default createReactClass({ // if this is the initial render and the flow we choose is SSO/CAS then go to it automatically // we do not do this when the user has changed to the server manually as that may be jarring. - if (initial && SSO_FLOWS.includes(flows[i].type)) { + // Only allow it when disable_custom_urls is asserted so that we don't prevent user from changing HS URL + if (initial && SdkConfig.get()['disable_custom_urls'] && SSO_FLOWS.includes(flows[i].type)) { const tmpCli = this._loginLogic.createTemporaryClient(); PlatformPeg.get().startSingleSignOn(tmpCli, flows[i].type === M_LOGIN_SSO ? "sso": "cas", true); } From 0f2e2ea069e9cdd5f05319370744aa354d450758 Mon Sep 17 00:00:00 2001 From: Zoe Date: Fri, 27 Mar 2020 11:58:54 +0000 Subject: [PATCH 09/37] Update shield display rules --- src/components/structures/RoomView.js | 8 +++++++- src/components/views/rooms/RoomTile.js | 7 ++++++- 2 files changed, 13 insertions(+), 2 deletions(-) diff --git a/src/components/structures/RoomView.js b/src/components/structures/RoomView.js index 5fd5f42f78..dd453667e0 100644 --- a/src/components/structures/RoomView.js +++ b/src/components/structures/RoomView.js @@ -40,6 +40,7 @@ import rate_limited_func from '../../ratelimitedfunc'; import * as ObjectUtils from '../../ObjectUtils'; import * as Rooms from '../../Rooms'; import eventSearch from '../../Searching'; +import DMRoomMap from '../../utils/DMRoomMap'; import {isOnlyCtrlOrCmdKeyEvent, Key} from '../../Keyboard'; @@ -833,7 +834,12 @@ export default createReactClass({ /* Check all verified user devices. */ /* Don't alarm if no other users are verified */ - const targets = (verified.length > 0) ? [...verified, this.context.getUserId()] : verified; + const isDM = !!DMRoomMap.shared().getUserIdForRoomId(this.props.room.roomId); + const includeUser = (verified.length > 0) && // Don't alarm for self in rooms where nobody else is verified + !isDM && // Don't alarm for self in DMs with other users + (e2eMembers.length != 2) || // Don't alarm for self in 1:1 chats with other users + (e2eMembers.length == 1); // Do alarm for self if we're alone in a room + const targets = includeUser ? [...verified, this.context.getUserId()] : verified; for (const userId of targets) { const devices = await this.context.getStoredDevicesForUser(userId); const anyDeviceNotVerified = devices.some(({deviceId}) => { diff --git a/src/components/views/rooms/RoomTile.js b/src/components/views/rooms/RoomTile.js index 0f44f5077a..6f9cd7f1be 100644 --- a/src/components/views/rooms/RoomTile.js +++ b/src/components/views/rooms/RoomTile.js @@ -167,7 +167,12 @@ export default createReactClass({ /* Check all verified user devices. */ /* Don't alarm if no other users are verified */ - const targets = (verified.length > 0) ? [...verified, cli.getUserId()] : verified; + const isDM = DMRoomMap.shared().getUserIdForRoomId(this.props.room.roomId); + const includeUser = (verified.length > 0) && // Don't alarm for self in rooms where nobody else is verified + !isDM && // Don't alarm for self in DMs with other users + (e2eMembers.length != 2) || // Don't alarm for self in 1:1 chats with other users + (e2eMembers.length == 1); // Do alarm for self if we're alone in a room + const targets = includeUser ? [...verified, cli.getUserId()] : verified; for (const userId of targets) { const devices = await cli.getStoredDevicesForUser(userId); const allDevicesVerified = devices.every(({deviceId}) => { From 5d7adef0a2a7d5de0ca9a7d7931c90e5fb52a213 Mon Sep 17 00:00:00 2001 From: Zoe Date: Fri, 27 Mar 2020 13:45:21 +0000 Subject: [PATCH 10/37] Factor out shield display rules into one file --- src/components/structures/RoomView.js | 39 ++-------------------- src/components/views/rooms/RoomTile.js | 36 ++------------------- src/utils/ShieldUtils.ts | 45 ++++++++++++++++++++++++++ 3 files changed, 50 insertions(+), 70 deletions(-) create mode 100644 src/utils/ShieldUtils.ts diff --git a/src/components/structures/RoomView.js b/src/components/structures/RoomView.js index dd453667e0..7ce50348c9 100644 --- a/src/components/structures/RoomView.js +++ b/src/components/structures/RoomView.js @@ -56,6 +56,7 @@ import RightPanelStore from "../../stores/RightPanelStore"; import {haveTileForEvent} from "../views/rooms/EventTile"; import RoomContext from "../../contexts/RoomContext"; import MatrixClientContext from "../../contexts/MatrixClientContext"; +import { shieldStatusForMembership } from '../../utils/ShieldUtils'; const DEBUG = false; let debuglog = function() {}; @@ -818,45 +819,9 @@ export default createReactClass({ return; } - // Duplication between here and _updateE2eStatus in RoomTile /* At this point, the user has encryption on and cross-signing on */ - const e2eMembers = await room.getEncryptionTargetMembers(); - const verified = []; - const unverified = []; - e2eMembers.map(({userId}) => userId) - .filter((userId) => userId !== this.context.getUserId()) - .forEach((userId) => { - (this.context.checkUserTrust(userId).isCrossSigningVerified() ? - verified : unverified).push(userId); - }); - - debuglog("e2e verified", verified, "unverified", unverified); - - /* Check all verified user devices. */ - /* Don't alarm if no other users are verified */ - const isDM = !!DMRoomMap.shared().getUserIdForRoomId(this.props.room.roomId); - const includeUser = (verified.length > 0) && // Don't alarm for self in rooms where nobody else is verified - !isDM && // Don't alarm for self in DMs with other users - (e2eMembers.length != 2) || // Don't alarm for self in 1:1 chats with other users - (e2eMembers.length == 1); // Do alarm for self if we're alone in a room - const targets = includeUser ? [...verified, this.context.getUserId()] : verified; - for (const userId of targets) { - const devices = await this.context.getStoredDevicesForUser(userId); - const anyDeviceNotVerified = devices.some(({deviceId}) => { - return !this.context.checkDeviceTrust(userId, deviceId).isVerified(); - }); - if (anyDeviceNotVerified) { - this.setState({ - e2eStatus: "warning", - }); - debuglog("e2e status set to warning as not all users trust all of their sessions." + - " Aborted on user", userId); - return; - } - } - this.setState({ - e2eStatus: unverified.length === 0 ? "verified" : "normal", + e2eStatus: await shieldStatusForMembership(this.context, room), }); }, diff --git a/src/components/views/rooms/RoomTile.js b/src/components/views/rooms/RoomTile.js index 6f9cd7f1be..478d6703b4 100644 --- a/src/components/views/rooms/RoomTile.js +++ b/src/components/views/rooms/RoomTile.js @@ -37,6 +37,7 @@ import E2EIcon from './E2EIcon'; import InviteOnlyIcon from './InviteOnlyIcon'; // eslint-disable-next-line camelcase import rate_limited_func from '../../../ratelimitedfunc'; +import { shieldStatusForMembership } from '../../../utils/ShieldUtils'; export default createReactClass({ displayName: 'RoomTile', @@ -154,40 +155,9 @@ export default createReactClass({ return; } - // Duplication between here and _updateE2eStatus in RoomView - const e2eMembers = await this.props.room.getEncryptionTargetMembers(); - const verified = []; - const unverified = []; - e2eMembers.map(({userId}) => userId) - .filter((userId) => userId !== cli.getUserId()) - .forEach((userId) => { - (cli.checkUserTrust(userId).isCrossSigningVerified() ? - verified : unverified).push(userId); - }); - - /* Check all verified user devices. */ - /* Don't alarm if no other users are verified */ - const isDM = DMRoomMap.shared().getUserIdForRoomId(this.props.room.roomId); - const includeUser = (verified.length > 0) && // Don't alarm for self in rooms where nobody else is verified - !isDM && // Don't alarm for self in DMs with other users - (e2eMembers.length != 2) || // Don't alarm for self in 1:1 chats with other users - (e2eMembers.length == 1); // Do alarm for self if we're alone in a room - const targets = includeUser ? [...verified, cli.getUserId()] : verified; - for (const userId of targets) { - const devices = await cli.getStoredDevicesForUser(userId); - const allDevicesVerified = devices.every(({deviceId}) => { - return cli.checkDeviceTrust(userId, deviceId).isVerified(); - }); - if (!allDevicesVerified) { - this.setState({ - e2eStatus: "warning", - }); - return; - } - } - + /* At this point, the user has encryption on and cross-signing on */ this.setState({ - e2eStatus: unverified.length === 0 ? "verified" : "normal", + e2eStatus: await shieldStatusForMembership(cli, this.props.room), }); }, diff --git a/src/utils/ShieldUtils.ts b/src/utils/ShieldUtils.ts new file mode 100644 index 0000000000..407dae8e97 --- /dev/null +++ b/src/utils/ShieldUtils.ts @@ -0,0 +1,45 @@ +import DMRoomMap from './DMRoomMap'; + +/* For now, a cut-down type spec for the client */ +interface Client { + getUserId: () => string; + checkUserTrust: (userId: string) => { + isCrossSigningVerified: () => boolean + }; + getStoredDevicesForUser: (userId: string) => Promise<[{ deviceId: string }]>; + checkDeviceTrust: (userId: string, deviceId: string) => { + isVerified: () => boolean + } +} + +export async function shieldStatusForMembership(client: Client, room) { + const members = (await room.getEncryptionTargetMembers()).map(({userId}) => userId); + const inDMMap = !!DMRoomMap.shared().getUserIdForRoomId(room.roomId); + + const verified = []; + const unverified = []; + members.filter((userId) => userId !== client.getUserId()) + .forEach((userId) => { + (client.checkUserTrust(userId).isCrossSigningVerified() ? + verified : unverified).push(userId); + }); + + /* Check all verified user devices. */ + /* Don't alarm if no other users are verified */ + const includeUser = (verified.length > 0) && // Don't alarm for self in rooms where nobody else is verified + !inDMMap && // Don't alarm for self in DMs with other users + (members.length != 2) || // Don't alarm for self in 1:1 chats with other users + (members.length == 1); // Do alarm for self if we're alone in a room + const targets = includeUser ? [...verified, client.getUserId()] : verified; + for (const userId of targets) { + const devices = await client.getStoredDevicesForUser(userId); + const anyDeviceNotVerified = devices.some(({deviceId}) => { + return !client.checkDeviceTrust(userId, deviceId).isVerified(); + }); + if (anyDeviceNotVerified) { + return "warning"; + } + } + + return unverified.length === 0 ? "verified" : "normal"; +} From 5b7e7f49d1cbc4733769f16a042b0a383d21c6c5 Mon Sep 17 00:00:00 2001 From: Zoe Date: Fri, 27 Mar 2020 13:50:03 +0000 Subject: [PATCH 11/37] lint --- src/components/structures/RoomView.js | 1 - src/utils/ShieldUtils.ts | 15 ++++++++++----- 2 files changed, 10 insertions(+), 6 deletions(-) diff --git a/src/components/structures/RoomView.js b/src/components/structures/RoomView.js index 7ce50348c9..74572b962a 100644 --- a/src/components/structures/RoomView.js +++ b/src/components/structures/RoomView.js @@ -40,7 +40,6 @@ import rate_limited_func from '../../ratelimitedfunc'; import * as ObjectUtils from '../../ObjectUtils'; import * as Rooms from '../../Rooms'; import eventSearch from '../../Searching'; -import DMRoomMap from '../../utils/DMRoomMap'; import {isOnlyCtrlOrCmdKeyEvent, Key} from '../../Keyboard'; diff --git a/src/utils/ShieldUtils.ts b/src/utils/ShieldUtils.ts index 407dae8e97..30b1dab7fc 100644 --- a/src/utils/ShieldUtils.ts +++ b/src/utils/ShieldUtils.ts @@ -12,12 +12,17 @@ interface Client { } } -export async function shieldStatusForMembership(client: Client, room) { +interface Room { + getEncryptionTargetMembers: () => Promise<[{userId: string}]>; + roomId: string; +} + +export async function shieldStatusForMembership(client: Client, room: Room) { const members = (await room.getEncryptionTargetMembers()).map(({userId}) => userId); const inDMMap = !!DMRoomMap.shared().getUserIdForRoomId(room.roomId); - const verified = []; - const unverified = []; + const verified: string[] = []; + const unverified: string[] = []; members.filter((userId) => userId !== client.getUserId()) .forEach((userId) => { (client.checkUserTrust(userId).isCrossSigningVerified() ? @@ -28,8 +33,8 @@ export async function shieldStatusForMembership(client: Client, room) { /* Don't alarm if no other users are verified */ const includeUser = (verified.length > 0) && // Don't alarm for self in rooms where nobody else is verified !inDMMap && // Don't alarm for self in DMs with other users - (members.length != 2) || // Don't alarm for self in 1:1 chats with other users - (members.length == 1); // Do alarm for self if we're alone in a room + (members.length !== 2) || // Don't alarm for self in 1:1 chats with other users + (members.length === 1); // Do alarm for self if we're alone in a room const targets = includeUser ? [...verified, client.getUserId()] : verified; for (const userId of targets) { const devices = await client.getStoredDevicesForUser(userId); From 1f0d7923d71fa1bc35d5774e5957a332ac427938 Mon Sep 17 00:00:00 2001 From: Zoe Date: Fri, 27 Mar 2020 13:51:30 +0000 Subject: [PATCH 12/37] with output type --- src/utils/ShieldUtils.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/utils/ShieldUtils.ts b/src/utils/ShieldUtils.ts index 30b1dab7fc..3c7cae8c8d 100644 --- a/src/utils/ShieldUtils.ts +++ b/src/utils/ShieldUtils.ts @@ -17,7 +17,7 @@ interface Room { roomId: string; } -export async function shieldStatusForMembership(client: Client, room: Room) { +export async function shieldStatusForMembership(client: Client, room: Room): Promise { const members = (await room.getEncryptionTargetMembers()).map(({userId}) => userId); const inDMMap = !!DMRoomMap.shared().getUserIdForRoomId(room.roomId); From db6f88c66a76736ce72ec0d22df6e6627b0a59ed Mon Sep 17 00:00:00 2001 From: Michael Telatynski <7t3chguy@gmail.com> Date: Fri, 27 Mar 2020 14:02:32 +0000 Subject: [PATCH 13/37] Welcome page, support $ssoUrl and $casUrl placeholders Signed-off-by: Michael Telatynski <7t3chguy@gmail.com> --- src/components/structures/EmbeddedPage.js | 9 +++++++++ src/components/structures/MatrixChat.js | 2 +- src/components/views/auth/Welcome.js | 15 ++++++++++++++- 3 files changed, 24 insertions(+), 2 deletions(-) diff --git a/src/components/structures/EmbeddedPage.js b/src/components/structures/EmbeddedPage.js index f854dc955f..a0a95ac6f1 100644 --- a/src/components/structures/EmbeddedPage.js +++ b/src/components/structures/EmbeddedPage.js @@ -37,6 +37,8 @@ export default class EmbeddedPage extends React.PureComponent { className: PropTypes.string, // Whether to wrap the page in a scrollbar scrollbar: PropTypes.bool, + // Map of keys to replace with values, e.g {$placeholder: "value"} + replaceMap: PropTypes.object, }; static contextType = MatrixClientContext; @@ -81,6 +83,13 @@ export default class EmbeddedPage extends React.PureComponent { } body = body.replace(/_t\(['"]([\s\S]*?)['"]\)/mg, (match, g1)=>this.translate(g1)); + + if (this.props.replaceMap) { + Object.keys(this.props.replaceMap).forEach(key => { + body = body.split(key).join(this.props.replaceMap[key]); + }); + } + this.setState({ page: body }); }, ); diff --git a/src/components/structures/MatrixChat.js b/src/components/structures/MatrixChat.js index 52002f0591..e6702e385e 100644 --- a/src/components/structures/MatrixChat.js +++ b/src/components/structures/MatrixChat.js @@ -2021,7 +2021,7 @@ export default createReactClass({ } } else if (this.state.view === VIEWS.WELCOME) { const Welcome = sdk.getComponent('auth.Welcome'); - view = ; + view = ; } else if (this.state.view === VIEWS.REGISTER) { const Registration = sdk.getComponent('structures.auth.Registration'); view = ( diff --git a/src/components/views/auth/Welcome.js b/src/components/views/auth/Welcome.js index 58f117ea36..60ceae5343 100644 --- a/src/components/views/auth/Welcome.js +++ b/src/components/views/auth/Welcome.js @@ -18,6 +18,7 @@ import React from 'react'; import * as sdk from '../../../index'; import SdkConfig from '../../../SdkConfig'; import AuthPage from "./AuthPage"; +import * as Matrix from "matrix-js-sdk"; export default class Welcome extends React.PureComponent { render() { @@ -33,11 +34,23 @@ export default class Welcome extends React.PureComponent { pageUrl = 'welcome.html'; } + const {hsUrl, isUrl} = this.props.serverConfig; + const tmpClient = Matrix.createClient({ + baseUrl: hsUrl, + idBaseUrl: isUrl, + }); + const callbackUrl = this.getSSOCallbackUrl(tmpClient.getHomeserverUrl(), tmpClient.getIdentityServerUrl()); + return (
-
From f4d3cc8ee62671336981f486561be58d4e3e0f6c Mon Sep 17 00:00:00 2001 From: Michael Telatynski <7t3chguy@gmail.com> Date: Fri, 27 Mar 2020 14:05:14 +0000 Subject: [PATCH 14/37] revert stale changes Signed-off-by: Michael Telatynski <7t3chguy@gmail.com> --- src/BasePlatform.js | 19 +----------------- src/components/structures/auth/Login.js | 26 +++++++------------------ src/components/views/auth/Welcome.js | 4 ++++ 3 files changed, 12 insertions(+), 37 deletions(-) diff --git a/src/BasePlatform.js b/src/BasePlatform.js index 489d9474a1..5d809eb28f 100644 --- a/src/BasePlatform.js +++ b/src/BasePlatform.js @@ -22,11 +22,6 @@ limitations under the License. import {MatrixClient} from "matrix-js-sdk"; import dis from './dispatcher'; import BaseEventIndexManager from './indexing/BaseEventIndexManager'; -import Modal from "./Modal"; -import InfoDialog from "./components/views/dialogs/InfoDialog"; -import {_t} from "./languageHandler"; -import Spinner from "./components/views/elements/Spinner"; -import React from "react"; /** * Base class for classes that provide platform-specific functionality @@ -188,21 +183,9 @@ export default class BasePlatform { * Begin Single Sign On flows. * @param {MatrixClient} mxClient the matrix client using which we should start the flow * @param {"sso"|"cas"} loginType the type of SSO it is, CAS/SSO. - * @param {boolean} showModal whether or not to show the spinner modal. */ - startSingleSignOn(mxClient: MatrixClient, loginType: "sso"|"cas", showModal: boolean) { + startSingleSignOn(mxClient: MatrixClient, loginType: "sso"|"cas") { const callbackUrl = this.getSSOCallbackUrl(mxClient.getHomeserverUrl(), mxClient.getIdentityServerUrl()); - if (showModal) { - Modal.createTrackedDialog('BasePlatform', 'SSO', InfoDialog, { - title: _t("Single sign-on"), - description: , - }); - } window.location.href = mxClient.getSsoLoginUrl(callbackUrl.toString(), loginType); // redirect to SSO } } diff --git a/src/components/structures/auth/Login.js b/src/components/structures/auth/Login.js index 134f6fa6f3..bfabc34a62 100644 --- a/src/components/structures/auth/Login.js +++ b/src/components/structures/auth/Login.js @@ -53,10 +53,6 @@ _td("Invalid base_url for m.identity_server"); _td("Identity server URL does not appear to be a valid identity server"); _td("General failure"); -const M_LOGIN_CAS = "m.login.cas"; -const M_LOGIN_SSO = "m.login.sso"; -const SSO_FLOWS = [M_LOGIN_SSO, M_LOGIN_CAS]; - /** * A wire component which glues together login UI components and Login logic */ @@ -126,11 +122,11 @@ export default createReactClass({ 'm.login.password': this._renderPasswordStep, // CAS and SSO are the same thing, modulo the url we link to - [M_LOGIN_CAS]: () => this._renderSsoStep("cas"), - [M_LOGIN_SSO]: () => this._renderSsoStep("sso"), + 'm.login.cas': () => this._renderSsoStep("cas"), + 'm.login.sso': () => this._renderSsoStep("sso"), }; - this._initLoginLogic(true); + this._initLoginLogic(); }, componentWillUnmount: function() { @@ -142,7 +138,7 @@ export default createReactClass({ newProps.serverConfig.isUrl === this.props.serverConfig.isUrl) return; // Ensure that we end up actually logging in to the right place - this._initLoginLogic(false, newProps.serverConfig.hsUrl, newProps.serverConfig.isUrl); + this._initLoginLogic(newProps.serverConfig.hsUrl, newProps.serverConfig.isUrl); }, onPasswordLoginError: function(errorText) { @@ -346,12 +342,12 @@ export default createReactClass({ onTryRegisterClick: function(ev) { const step = this._getCurrentFlowStep(); - if (SSO_FLOWS.includes(step)) { + if (step === 'm.login.sso' || step === 'm.login.cas') { // If we're showing SSO it means that registration is also probably disabled, // so intercept the click and instead pretend the user clicked 'Sign in with SSO'. ev.preventDefault(); ev.stopPropagation(); - const ssoKind = step === M_LOGIN_SSO ? 'sso' : 'cas'; + const ssoKind = step === 'm.login.sso' ? 'sso' : 'cas'; PlatformPeg.get().startSingleSignOn(this._loginLogic.createTemporaryClient(), ssoKind); } else { // Don't intercept - just go through to the register page @@ -373,7 +369,7 @@ export default createReactClass({ }); }, - _initLoginLogic: async function(initial, hsUrl, isUrl) { + _initLoginLogic: async function(hsUrl, isUrl) { hsUrl = hsUrl || this.props.serverConfig.hsUrl; isUrl = isUrl || this.props.serverConfig.isUrl; @@ -433,14 +429,6 @@ export default createReactClass({ continue; } - // if this is the initial render and the flow we choose is SSO/CAS then go to it automatically - // we do not do this when the user has changed to the server manually as that may be jarring. - // Only allow it when disable_custom_urls is asserted so that we don't prevent user from changing HS URL - if (initial && SdkConfig.get()['disable_custom_urls'] && SSO_FLOWS.includes(flows[i].type)) { - const tmpCli = this._loginLogic.createTemporaryClient(); - PlatformPeg.get().startSingleSignOn(tmpCli, flows[i].type === M_LOGIN_SSO ? "sso": "cas", true); - } - // we just pick the first flow where we support all the // steps. (we don't have a UI for multiple logins so let's skip // that for now). diff --git a/src/components/views/auth/Welcome.js b/src/components/views/auth/Welcome.js index 60ceae5343..70c5569cd9 100644 --- a/src/components/views/auth/Welcome.js +++ b/src/components/views/auth/Welcome.js @@ -19,6 +19,10 @@ import * as sdk from '../../../index'; import SdkConfig from '../../../SdkConfig'; import AuthPage from "./AuthPage"; import * as Matrix from "matrix-js-sdk"; +import {_td} from "../../../languageHandler"; + +// translatable strings for Welcome pages +_td("Sign in with SSO"); export default class Welcome extends React.PureComponent { render() { From 6664535a269da603a88562f1cf943d405d2c425e Mon Sep 17 00:00:00 2001 From: Michael Telatynski <7t3chguy@gmail.com> Date: Fri, 27 Mar 2020 14:05:32 +0000 Subject: [PATCH 15/37] change welcome page placeholders Signed-off-by: Michael Telatynski <7t3chguy@gmail.com> --- src/components/views/auth/Welcome.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/components/views/auth/Welcome.js b/src/components/views/auth/Welcome.js index 70c5569cd9..1893b04d76 100644 --- a/src/components/views/auth/Welcome.js +++ b/src/components/views/auth/Welcome.js @@ -52,8 +52,8 @@ export default class Welcome extends React.PureComponent { className="mx_WelcomePage" url={pageUrl} replaceMap={{ - "$ssoUrl": tmpClient.getSsoLoginUrl(callbackUrl.toString(), "sso"), - "$casUrl": tmpClient.getSsoLoginUrl(callbackUrl.toString(), "cas"), + "$riot:ssoUrl": tmpClient.getSsoLoginUrl(callbackUrl.toString(), "sso"), + "$riot:casUrl": tmpClient.getSsoLoginUrl(callbackUrl.toString(), "cas"), }} /> From de0895b88193aca8e01c61b4e175a7812317dfa2 Mon Sep 17 00:00:00 2001 From: Michael Telatynski <7t3chguy@gmail.com> Date: Fri, 27 Mar 2020 14:06:21 +0000 Subject: [PATCH 16/37] i18n Signed-off-by: Michael Telatynski <7t3chguy@gmail.com> --- src/i18n/strings/en_EN.json | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/i18n/strings/en_EN.json b/src/i18n/strings/en_EN.json index 4677f40ce1..fbb3fd9f6f 100644 --- a/src/i18n/strings/en_EN.json +++ b/src/i18n/strings/en_EN.json @@ -25,8 +25,6 @@ "Error": "Error", "Unable to load! Check your network connectivity and try again.": "Unable to load! Check your network connectivity and try again.", "Dismiss": "Dismiss", - "Single sign-on": "Single sign-on", - "Click here if you're not redirected automatically": "Click here if you're not redirected automatically", "Call Failed": "Call Failed", "There are unknown sessions in this room: if you proceed without verifying them, it will be possible for someone to eavesdrop on your call.": "There are unknown sessions in this room: if you proceed without verifying them, it will be possible for someone to eavesdrop on your call.", "Review Sessions": "Review Sessions", @@ -1872,6 +1870,7 @@ "Find other public servers or use a custom server": "Find other public servers or use a custom server", "Sign in to your Matrix account on %(serverName)s": "Sign in to your Matrix account on %(serverName)s", "Sign in to your Matrix account on ": "Sign in to your Matrix account on ", + "Sign in with SSO": "Sign in with SSO", "Sorry, your browser is not able to run Riot.": "Sorry, your browser is not able to run Riot.", "Riot uses many advanced browser features, some of which are not available or experimental in your current browser.": "Riot uses many advanced browser features, some of which are not available or experimental in your current browser.", "Please install Chrome, Firefox, or Safari for the best experience.": "Please install Chrome, Firefox, or Safari for the best experience.", From 9d0ed6e80040502fb8d8c3db359826133c97ab53 Mon Sep 17 00:00:00 2001 From: Michael Telatynski <7t3chguy@gmail.com> Date: Fri, 27 Mar 2020 14:19:43 +0000 Subject: [PATCH 17/37] fix copy-pasta error Signed-off-by: Michael Telatynski <7t3chguy@gmail.com> --- src/components/views/auth/Welcome.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/components/views/auth/Welcome.js b/src/components/views/auth/Welcome.js index 1893b04d76..7cbcf65d3c 100644 --- a/src/components/views/auth/Welcome.js +++ b/src/components/views/auth/Welcome.js @@ -20,6 +20,7 @@ import SdkConfig from '../../../SdkConfig'; import AuthPage from "./AuthPage"; import * as Matrix from "matrix-js-sdk"; import {_td} from "../../../languageHandler"; +import PlatformPeg from "../../../PlatformPeg"; // translatable strings for Welcome pages _td("Sign in with SSO"); @@ -43,7 +44,8 @@ export default class Welcome extends React.PureComponent { baseUrl: hsUrl, idBaseUrl: isUrl, }); - const callbackUrl = this.getSSOCallbackUrl(tmpClient.getHomeserverUrl(), tmpClient.getIdentityServerUrl()); + const plaf = PlatformPeg.get(); + const callbackUrl = plaf.getSSOCallbackUrl(tmpClient.getHomeserverUrl(), tmpClient.getIdentityServerUrl()); return ( From fda533ab48321e09de49ccb3b356171a09918bda Mon Sep 17 00:00:00 2001 From: Zoe Date: Fri, 27 Mar 2020 15:25:44 +0000 Subject: [PATCH 18/37] test for shield behaviour --- test/utils/ShieldUtils-test.js | 170 +++++++++++++++++++++++++++++++++ 1 file changed, 170 insertions(+) create mode 100644 test/utils/ShieldUtils-test.js diff --git a/test/utils/ShieldUtils-test.js b/test/utils/ShieldUtils-test.js new file mode 100644 index 0000000000..5030d9c5c8 --- /dev/null +++ b/test/utils/ShieldUtils-test.js @@ -0,0 +1,170 @@ +import { shieldStatusForMembership } from '../../src/utils/ShieldUtils'; +import DMRoomMap from '../../src/utils/DMRoomMap'; + +function mkClient (selfTrust) { + return { + getUserId: () => "@self:localhost", + checkUserTrust: (userId) => ({ + isCrossSigningVerified: () => userId[1] == "T" + }), + checkDeviceTrust: (userId, deviceId) => ({ + isVerified: () => userId === "@self:localhost" ? selfTrust : userId[2] == "T" + }), + getStoredDevicesForUser: async (userId) => ["DEVICE"], + } +} + +describe("mkClient self-test", function () { + test.each([true, false])("behaves well for self-trust=%s", (v) => { + const client = mkClient(v); + expect(client.checkDeviceTrust("@self:localhost", "DEVICE").isVerified()).toBe(v); + }); + + test.each([ + ["@TT:h", true], + ["@TF:h", true], + ["@FT:h", false], + ["@FF:h", false]]) + ("behaves well for user trust %s", (userId, trust) => { + expect(mkClient().checkUserTrust(userId).isCrossSigningVerified()).toBe(trust); + }); + + test.each([ + ["@TT:h", true], + ["@TF:h", false], + ["@FT:h", true], + ["@FF:h", false]]) + ("behaves well for device trust %s", (userId, trust) => { + expect(mkClient().checkDeviceTrust(userId, "device").isVerified()).toBe(trust); + }); +}); + +describe("shieldStatusForMembership self-trust behaviour", function () { + beforeAll(() => { + DMRoomMap._sharedInstance = { + getUserIdForRoomId: (roomId) => roomId === "DM" ? "@any:h" : null, + }; + }); + + it.each( + [[true, true], [true, false], + [false, true], [false, false]] + )("2 unverified: returns 'normal', self-trust = %s, DM = %s", async (trusted, dm) => { + const client = mkClient(trusted); + const room = { + roomId: dm ? "DM" : "other", + getEncryptionTargetMembers: () => ["@self:localhost", "@FF1:h", "@FF2:h"].map((userId) => ({userId})), + } + const status = await shieldStatusForMembership(client, room); + expect(status).toEqual("normal"); + }); + + it.each( + [["verified", true, true], ["verified", true, false], + ["verified", false, true], ["warning", false, false]] + )("2 verified: returns '%s', self-trust = %s, DM = %s", async (result, trusted, dm) => { + const client = mkClient(trusted); + const room = { + roomId: dm ? "DM" : "other", + getEncryptionTargetMembers: () => ["@self:localhost", "@TT1:h", "@TT2:h"].map((userId) => ({userId})), + } + const status = await shieldStatusForMembership(client, room); + expect(status).toEqual(result); + }); + + it.each( + [["normal", true, true], ["normal", true, false], + ["normal", false, true], ["warning", false, false]] + )("2 mixed: returns '%s', self-trust = %s, DM = %s", async (result, trusted, dm) => { + const client = mkClient(trusted); + const room = { + roomId: dm ? "DM" : "other", + getEncryptionTargetMembers: () => ["@self:localhost", "@TT1:h", "@FF2:h"].map((userId) => ({userId})), + } + const status = await shieldStatusForMembership(client, room); + expect(status).toEqual(result); + }); + + it.each( + [["verified", true, true], ["verified", true, false], + ["warning", false, true], ["warning", false, false]] + )("0 others: returns '%s', self-trust = %s, DM = %s", async (result, trusted, dm) => { + const client = mkClient(trusted); + const room = { + roomId: dm ? "DM" : "other", + getEncryptionTargetMembers: () => ["@self:localhost"].map((userId) => ({userId})), + } + const status = await shieldStatusForMembership(client, room); + expect(status).toEqual(result); + }); + + it.each( + [["verified", true, true], ["verified", true, false], + ["verified", false, true], ["verified", false, false]] + )("1 verified: returns '%s', self-trust = %s, DM = %s", async (result, trusted, dm) => { + const client = mkClient(trusted); + const room = { + roomId: dm ? "DM" : "other", + getEncryptionTargetMembers: () => ["@self:localhost", "@TT:h"].map((userId) => ({userId})), + } + const status = await shieldStatusForMembership(client, room); + expect(status).toEqual(result); + }); + + it.each( + [["normal", true, true], ["normal", true, false], + ["normal", false, true], ["normal", false, false]] + )("1 unverified: returns '%s', self-trust = %s, DM = %s", async (result, trusted, dm) => { + const client = mkClient(trusted); + const room = { + roomId: dm ? "DM" : "other", + getEncryptionTargetMembers: () => ["@self:localhost", "@FF:h"].map((userId) => ({userId})), + } + const status = await shieldStatusForMembership(client, room); + expect(status).toEqual(result); + }); +}); + +describe("shieldStatusForMembership other-trust behaviour", function () { + beforeAll(() => { + DMRoomMap._sharedInstance = { + getUserIdForRoomId: (roomId) => roomId === "DM" ? "@any:h" : null, + }; + }); + + it.each( + [["warning", true], ["warning", false]] + )("1 verified/untrusted: returns '%s', DM = %s", async (result, dm) => { + const client = mkClient(true); + const room = { + roomId: dm ? "DM" : "other", + getEncryptionTargetMembers: () => ["@self:localhost", "@TF:h"].map((userId) => ({userId})), + } + const status = await shieldStatusForMembership(client, room); + expect(status).toEqual(result); + }); + + it.each( + [["warning", true], ["warning", false]] + )("2 verified/untrusted: returns '%s', DM = %s", async (result, dm) => { + const client = mkClient(true); + const room = { + roomId: dm ? "DM" : "other", + getEncryptionTargetMembers: () => ["@self:localhost", "@TF:h", "@TT: h"].map((userId) => ({userId})), + } + const status = await shieldStatusForMembership(client, room); + expect(status).toEqual(result); + }); + + it.each( + [["normal", true], ["normal", false]] + )("2 unverified/untrusted: returns '%s', DM = %s", async (result, dm) => { + const client = mkClient(true); + const room = { + roomId: dm ? "DM" : "other", + getEncryptionTargetMembers: () => ["@self:localhost", "@FF:h", "@FT: h"].map((userId) => ({userId})), + } + const status = await shieldStatusForMembership(client, room); + expect(status).toEqual(result); + }); +}); From 4f3d4426ea05a9d7a8a0846f3422d13039eab27d Mon Sep 17 00:00:00 2001 From: Zoe Date: Fri, 27 Mar 2020 15:37:59 +0000 Subject: [PATCH 19/37] lint --- test/utils/ShieldUtils-test.js | 58 +++++++++++++++++----------------- 1 file changed, 29 insertions(+), 29 deletions(-) diff --git a/test/utils/ShieldUtils-test.js b/test/utils/ShieldUtils-test.js index 5030d9c5c8..973798fa4b 100644 --- a/test/utils/ShieldUtils-test.js +++ b/test/utils/ShieldUtils-test.js @@ -1,20 +1,20 @@ import { shieldStatusForMembership } from '../../src/utils/ShieldUtils'; import DMRoomMap from '../../src/utils/DMRoomMap'; -function mkClient (selfTrust) { +function mkClient(selfTrust) { return { getUserId: () => "@self:localhost", checkUserTrust: (userId) => ({ - isCrossSigningVerified: () => userId[1] == "T" + isCrossSigningVerified: () => userId[1] == "T", }), checkDeviceTrust: (userId, deviceId) => ({ - isVerified: () => userId === "@self:localhost" ? selfTrust : userId[2] == "T" + isVerified: () => userId === "@self:localhost" ? selfTrust : userId[2] == "T", }), getStoredDevicesForUser: async (userId) => ["DEVICE"], - } + }; } -describe("mkClient self-test", function () { +describe("mkClient self-test", function() { test.each([true, false])("behaves well for self-trust=%s", (v) => { const client = mkClient(v); expect(client.checkDeviceTrust("@self:localhost", "DEVICE").isVerified()).toBe(v); @@ -24,8 +24,8 @@ describe("mkClient self-test", function () { ["@TT:h", true], ["@TF:h", true], ["@FT:h", false], - ["@FF:h", false]]) - ("behaves well for user trust %s", (userId, trust) => { + ["@FF:h", false]], + )("behaves well for user trust %s", (userId, trust) => { expect(mkClient().checkUserTrust(userId).isCrossSigningVerified()).toBe(trust); }); @@ -33,13 +33,13 @@ describe("mkClient self-test", function () { ["@TT:h", true], ["@TF:h", false], ["@FT:h", true], - ["@FF:h", false]]) - ("behaves well for device trust %s", (userId, trust) => { + ["@FF:h", false]], + )("behaves well for device trust %s", (userId, trust) => { expect(mkClient().checkDeviceTrust(userId, "device").isVerified()).toBe(trust); }); }); -describe("shieldStatusForMembership self-trust behaviour", function () { +describe("shieldStatusForMembership self-trust behaviour", function() { beforeAll(() => { DMRoomMap._sharedInstance = { getUserIdForRoomId: (roomId) => roomId === "DM" ? "@any:h" : null, @@ -48,84 +48,84 @@ describe("shieldStatusForMembership self-trust behaviour", function () { it.each( [[true, true], [true, false], - [false, true], [false, false]] + [false, true], [false, false]], )("2 unverified: returns 'normal', self-trust = %s, DM = %s", async (trusted, dm) => { const client = mkClient(trusted); const room = { roomId: dm ? "DM" : "other", getEncryptionTargetMembers: () => ["@self:localhost", "@FF1:h", "@FF2:h"].map((userId) => ({userId})), - } + }; const status = await shieldStatusForMembership(client, room); expect(status).toEqual("normal"); }); it.each( [["verified", true, true], ["verified", true, false], - ["verified", false, true], ["warning", false, false]] + ["verified", false, true], ["warning", false, false]], )("2 verified: returns '%s', self-trust = %s, DM = %s", async (result, trusted, dm) => { const client = mkClient(trusted); const room = { roomId: dm ? "DM" : "other", getEncryptionTargetMembers: () => ["@self:localhost", "@TT1:h", "@TT2:h"].map((userId) => ({userId})), - } + }; const status = await shieldStatusForMembership(client, room); expect(status).toEqual(result); }); it.each( [["normal", true, true], ["normal", true, false], - ["normal", false, true], ["warning", false, false]] + ["normal", false, true], ["warning", false, false]], )("2 mixed: returns '%s', self-trust = %s, DM = %s", async (result, trusted, dm) => { const client = mkClient(trusted); const room = { roomId: dm ? "DM" : "other", getEncryptionTargetMembers: () => ["@self:localhost", "@TT1:h", "@FF2:h"].map((userId) => ({userId})), - } + }; const status = await shieldStatusForMembership(client, room); expect(status).toEqual(result); }); it.each( [["verified", true, true], ["verified", true, false], - ["warning", false, true], ["warning", false, false]] + ["warning", false, true], ["warning", false, false]], )("0 others: returns '%s', self-trust = %s, DM = %s", async (result, trusted, dm) => { const client = mkClient(trusted); const room = { roomId: dm ? "DM" : "other", getEncryptionTargetMembers: () => ["@self:localhost"].map((userId) => ({userId})), - } + }; const status = await shieldStatusForMembership(client, room); expect(status).toEqual(result); }); it.each( [["verified", true, true], ["verified", true, false], - ["verified", false, true], ["verified", false, false]] + ["verified", false, true], ["verified", false, false]], )("1 verified: returns '%s', self-trust = %s, DM = %s", async (result, trusted, dm) => { const client = mkClient(trusted); const room = { roomId: dm ? "DM" : "other", getEncryptionTargetMembers: () => ["@self:localhost", "@TT:h"].map((userId) => ({userId})), - } + }; const status = await shieldStatusForMembership(client, room); expect(status).toEqual(result); }); it.each( [["normal", true, true], ["normal", true, false], - ["normal", false, true], ["normal", false, false]] + ["normal", false, true], ["normal", false, false]], )("1 unverified: returns '%s', self-trust = %s, DM = %s", async (result, trusted, dm) => { const client = mkClient(trusted); const room = { roomId: dm ? "DM" : "other", getEncryptionTargetMembers: () => ["@self:localhost", "@FF:h"].map((userId) => ({userId})), - } + }; const status = await shieldStatusForMembership(client, room); expect(status).toEqual(result); }); }); -describe("shieldStatusForMembership other-trust behaviour", function () { +describe("shieldStatusForMembership other-trust behaviour", function() { beforeAll(() => { DMRoomMap._sharedInstance = { getUserIdForRoomId: (roomId) => roomId === "DM" ? "@any:h" : null, @@ -133,37 +133,37 @@ describe("shieldStatusForMembership other-trust behaviour", function () { }); it.each( - [["warning", true], ["warning", false]] + [["warning", true], ["warning", false]], )("1 verified/untrusted: returns '%s', DM = %s", async (result, dm) => { const client = mkClient(true); const room = { roomId: dm ? "DM" : "other", getEncryptionTargetMembers: () => ["@self:localhost", "@TF:h"].map((userId) => ({userId})), - } + }; const status = await shieldStatusForMembership(client, room); expect(status).toEqual(result); }); it.each( - [["warning", true], ["warning", false]] + [["warning", true], ["warning", false]], )("2 verified/untrusted: returns '%s', DM = %s", async (result, dm) => { const client = mkClient(true); const room = { roomId: dm ? "DM" : "other", getEncryptionTargetMembers: () => ["@self:localhost", "@TF:h", "@TT: h"].map((userId) => ({userId})), - } + }; const status = await shieldStatusForMembership(client, room); expect(status).toEqual(result); }); it.each( - [["normal", true], ["normal", false]] + [["normal", true], ["normal", false]], )("2 unverified/untrusted: returns '%s', DM = %s", async (result, dm) => { const client = mkClient(true); const room = { roomId: dm ? "DM" : "other", getEncryptionTargetMembers: () => ["@self:localhost", "@FF:h", "@FT: h"].map((userId) => ({userId})), - } + }; const status = await shieldStatusForMembership(client, room); expect(status).toEqual(result); }); From 37619dd127b8d76858452bac016c40f49cfed094 Mon Sep 17 00:00:00 2001 From: "J. Ryan Stinnett" Date: Sat, 28 Mar 2020 00:21:17 +0000 Subject: [PATCH 20/37] Show red shield for users that become unverified For any users that we previously verified but that are not unverified, we will now mark them and rooms they are in with a red shield. Fixes https://github.com/vector-im/riot-web/issues/12808 --- src/components/views/right_panel/UserInfo.js | 6 ++++-- src/components/views/rooms/MemberTile.js | 6 +++--- src/utils/ShieldUtils.ts | 8 ++++++++ 3 files changed, 15 insertions(+), 5 deletions(-) diff --git a/src/components/views/right_panel/UserInfo.js b/src/components/views/right_panel/UserInfo.js index ee47f08aa2..a2081dc9e4 100644 --- a/src/components/views/right_panel/UserInfo.js +++ b/src/components/views/right_panel/UserInfo.js @@ -68,8 +68,10 @@ export const getE2EStatus = (cli, userId, devices) => { return hasUnverifiedDevice ? "warning" : "verified"; } const isMe = userId === cli.getUserId(); - const userVerified = cli.checkUserTrust(userId).isCrossSigningVerified(); - if (!userVerified) return "normal"; + const userTrust = cli.checkUserTrust(userId); + if (!userTrust.isCrossSigningVerified()) { + return userTrust.wasCrossSigningVerified() ? "warning" : "normal"; + } const anyDeviceUnverified = devices.some(device => { const { deviceId } = device; diff --git a/src/components/views/rooms/MemberTile.js b/src/components/views/rooms/MemberTile.js index a0e900b5fc..bf2a1bee23 100644 --- a/src/components/views/rooms/MemberTile.js +++ b/src/components/views/rooms/MemberTile.js @@ -121,10 +121,10 @@ export default createReactClass({ const cli = MatrixClientPeg.get(); const { userId } = this.props.member; const isMe = userId === cli.getUserId(); - const userVerified = cli.checkUserTrust(userId).isCrossSigningVerified(); - if (!userVerified) { + const userTrust = cli.checkUserTrust(userId); + if (!userTrust.isCrossSigningVerified()) { this.setState({ - e2eStatus: "normal", + e2eStatus: userTrust.wasCrossSigningVerified() ? "warning" : "normal", }); return; } diff --git a/src/utils/ShieldUtils.ts b/src/utils/ShieldUtils.ts index 3c7cae8c8d..f427b0b0b6 100644 --- a/src/utils/ShieldUtils.ts +++ b/src/utils/ShieldUtils.ts @@ -5,6 +5,7 @@ interface Client { getUserId: () => string; checkUserTrust: (userId: string) => { isCrossSigningVerified: () => boolean + wasCrossSigningVerified: () => boolean }; getStoredDevicesForUser: (userId: string) => Promise<[{ deviceId: string }]>; checkDeviceTrust: (userId: string, deviceId: string) => { @@ -29,6 +30,13 @@ export async function shieldStatusForMembership(client: Client, room: Room): Pro verified : unverified).push(userId); }); + /* Alarm if any unverified users were verified before. */ + for (const userId of unverified) { + if (client.checkUserTrust(userId).wasCrossSigningVerified()) { + return "warning"; + } + } + /* Check all verified user devices. */ /* Don't alarm if no other users are verified */ const includeUser = (verified.length > 0) && // Don't alarm for self in rooms where nobody else is verified From b2d905ef2c7c53ba4f07e442a6414c1a7c0976be Mon Sep 17 00:00:00 2001 From: Michael Telatynski <7t3chguy@gmail.com> Date: Sun, 29 Mar 2020 20:07:32 +0100 Subject: [PATCH 21/37] Make FormatButton use AccessibleButtons Signed-off-by: Michael Telatynski <7t3chguy@gmail.com> --- .../views/rooms/MessageComposerFormatBar.js | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/src/components/views/rooms/MessageComposerFormatBar.js b/src/components/views/rooms/MessageComposerFormatBar.js index 79ae9f34e8..42d54f5987 100644 --- a/src/components/views/rooms/MessageComposerFormatBar.js +++ b/src/components/views/rooms/MessageComposerFormatBar.js @@ -19,12 +19,13 @@ import PropTypes from 'prop-types'; import { _t } from '../../../languageHandler'; import * as sdk from '../../../index'; import classNames from 'classnames'; +import AccessibleButton from "../elements/AccessibleButton"; export default class MessageComposerFormatBar extends React.PureComponent { static propTypes = { onAction: PropTypes.func.isRequired, shortcuts: PropTypes.object.isRequired, - } + }; constructor(props) { super(props); @@ -64,7 +65,7 @@ class FormatButton extends React.PureComponent { icon: PropTypes.string.isRequired, shortcut: PropTypes.string, visible: PropTypes.bool, - } + }; render() { const InteractiveTooltip = sdk.getComponent('elements.InteractiveTooltip'); @@ -82,11 +83,12 @@ class FormatButton extends React.PureComponent { return ( - - + ); } From 2ff16844e5b1b97f3de5ca391a96b2ad59129fc4 Mon Sep 17 00:00:00 2001 From: Michael Telatynski <7t3chguy@gmail.com> Date: Sun, 29 Mar 2020 20:12:10 +0100 Subject: [PATCH 22/37] Make ELS somewhat more accessible Signed-off-by: Michael Telatynski <7t3chguy@gmail.com> --- .../views/elements/EventListSummary.js | 35 ++++++++++--------- 1 file changed, 18 insertions(+), 17 deletions(-) diff --git a/src/components/views/elements/EventListSummary.js b/src/components/views/elements/EventListSummary.js index 7a69398071..79c84293c2 100644 --- a/src/components/views/elements/EventListSummary.js +++ b/src/components/views/elements/EventListSummary.js @@ -20,6 +20,7 @@ import MemberAvatar from '../avatars/MemberAvatar'; import { _t } from '../../../languageHandler'; import {MatrixEvent, RoomMember} from "matrix-js-sdk"; import {useStateToggle} from "../../../hooks/useStateToggle"; +import AccessibleButton from "./AccessibleButton"; const EventListSummary = ({events, children, threshold=3, onToggle, startExpanded, summaryMembers=[], summaryText}) => { const [expanded, toggleExpanded] = useStateToggle(startExpanded); @@ -42,24 +43,15 @@ const EventListSummary = ({events, children, threshold=3, onToggle, startExpande ); } + let body; if (expanded) { - return ( -
-
- { _t('collapse') } -
-
 
- { children } -
- ); - } - - const avatars = summaryMembers.map((m) => ); - return ( -
-
- { _t('expand') } -
+ body = +
 
+ { children } +
; + } else { + const avatars = summaryMembers.map((m) => ); + body = (
@@ -70,6 +62,15 @@ const EventListSummary = ({events, children, threshold=3, onToggle, startExpande
+ ); + } + + return ( +
+ + { expanded ? _t('collapse') : _t('expand') } + + { body }
); }; From 098df07c67ed41b7698b9cda0b0beaa2ecf525db Mon Sep 17 00:00:00 2001 From: Zoe Date: Mon, 30 Mar 2020 10:18:47 +0100 Subject: [PATCH 23/37] review feedback --- src/components/structures/RoomView.js | 4 ++-- src/components/views/rooms/RoomTile.js | 4 ++-- src/utils/ShieldUtils.ts | 6 +++--- test/utils/ShieldUtils-test.js | 20 ++++++++++---------- 4 files changed, 17 insertions(+), 17 deletions(-) diff --git a/src/components/structures/RoomView.js b/src/components/structures/RoomView.js index 74572b962a..1a1f60c7bd 100644 --- a/src/components/structures/RoomView.js +++ b/src/components/structures/RoomView.js @@ -55,7 +55,7 @@ import RightPanelStore from "../../stores/RightPanelStore"; import {haveTileForEvent} from "../views/rooms/EventTile"; import RoomContext from "../../contexts/RoomContext"; import MatrixClientContext from "../../contexts/MatrixClientContext"; -import { shieldStatusForMembership } from '../../utils/ShieldUtils'; +import { shieldStatusForRoom } from '../../utils/ShieldUtils'; const DEBUG = false; let debuglog = function() {}; @@ -820,7 +820,7 @@ export default createReactClass({ /* At this point, the user has encryption on and cross-signing on */ this.setState({ - e2eStatus: await shieldStatusForMembership(this.context, room), + e2eStatus: await shieldStatusForRoom(this.context, room), }); }, diff --git a/src/components/views/rooms/RoomTile.js b/src/components/views/rooms/RoomTile.js index 478d6703b4..0c913b32da 100644 --- a/src/components/views/rooms/RoomTile.js +++ b/src/components/views/rooms/RoomTile.js @@ -37,7 +37,7 @@ import E2EIcon from './E2EIcon'; import InviteOnlyIcon from './InviteOnlyIcon'; // eslint-disable-next-line camelcase import rate_limited_func from '../../../ratelimitedfunc'; -import { shieldStatusForMembership } from '../../../utils/ShieldUtils'; +import { shieldStatusForRoom } from '../../../utils/ShieldUtils'; export default createReactClass({ displayName: 'RoomTile', @@ -157,7 +157,7 @@ export default createReactClass({ /* At this point, the user has encryption on and cross-signing on */ this.setState({ - e2eStatus: await shieldStatusForMembership(cli, this.props.room), + e2eStatus: await shieldStatusForRoom(cli, this.props.room), }); }, diff --git a/src/utils/ShieldUtils.ts b/src/utils/ShieldUtils.ts index 3c7cae8c8d..ef2d475293 100644 --- a/src/utils/ShieldUtils.ts +++ b/src/utils/ShieldUtils.ts @@ -17,7 +17,7 @@ interface Room { roomId: string; } -export async function shieldStatusForMembership(client: Client, room: Room): Promise { +export async function shieldStatusForRoom(client: Client, room: Room): Promise { const members = (await room.getEncryptionTargetMembers()).map(({userId}) => userId); const inDMMap = !!DMRoomMap.shared().getUserIdForRoomId(room.roomId); @@ -33,8 +33,8 @@ export async function shieldStatusForMembership(client: Client, room: Room): Pro /* Don't alarm if no other users are verified */ const includeUser = (verified.length > 0) && // Don't alarm for self in rooms where nobody else is verified !inDMMap && // Don't alarm for self in DMs with other users - (members.length !== 2) || // Don't alarm for self in 1:1 chats with other users - (members.length === 1); // Do alarm for self if we're alone in a room + (members.length !== 2) || // Don't alarm for self in 1:1 chats with other users + (members.length === 1); // Do alarm for self if we're alone in a room const targets = includeUser ? [...verified, client.getUserId()] : verified; for (const userId of targets) { const devices = await client.getStoredDevicesForUser(userId); diff --git a/test/utils/ShieldUtils-test.js b/test/utils/ShieldUtils-test.js index 973798fa4b..949f0ed42b 100644 --- a/test/utils/ShieldUtils-test.js +++ b/test/utils/ShieldUtils-test.js @@ -1,4 +1,4 @@ -import { shieldStatusForMembership } from '../../src/utils/ShieldUtils'; +import { shieldStatusForRoom } from '../../src/utils/ShieldUtils'; import DMRoomMap from '../../src/utils/DMRoomMap'; function mkClient(selfTrust) { @@ -55,7 +55,7 @@ describe("shieldStatusForMembership self-trust behaviour", function() { roomId: dm ? "DM" : "other", getEncryptionTargetMembers: () => ["@self:localhost", "@FF1:h", "@FF2:h"].map((userId) => ({userId})), }; - const status = await shieldStatusForMembership(client, room); + const status = await shieldStatusForRoom(client, room); expect(status).toEqual("normal"); }); @@ -68,7 +68,7 @@ describe("shieldStatusForMembership self-trust behaviour", function() { roomId: dm ? "DM" : "other", getEncryptionTargetMembers: () => ["@self:localhost", "@TT1:h", "@TT2:h"].map((userId) => ({userId})), }; - const status = await shieldStatusForMembership(client, room); + const status = await shieldStatusForRoom(client, room); expect(status).toEqual(result); }); @@ -81,7 +81,7 @@ describe("shieldStatusForMembership self-trust behaviour", function() { roomId: dm ? "DM" : "other", getEncryptionTargetMembers: () => ["@self:localhost", "@TT1:h", "@FF2:h"].map((userId) => ({userId})), }; - const status = await shieldStatusForMembership(client, room); + const status = await shieldStatusForRoom(client, room); expect(status).toEqual(result); }); @@ -94,7 +94,7 @@ describe("shieldStatusForMembership self-trust behaviour", function() { roomId: dm ? "DM" : "other", getEncryptionTargetMembers: () => ["@self:localhost"].map((userId) => ({userId})), }; - const status = await shieldStatusForMembership(client, room); + const status = await shieldStatusForRoom(client, room); expect(status).toEqual(result); }); @@ -107,7 +107,7 @@ describe("shieldStatusForMembership self-trust behaviour", function() { roomId: dm ? "DM" : "other", getEncryptionTargetMembers: () => ["@self:localhost", "@TT:h"].map((userId) => ({userId})), }; - const status = await shieldStatusForMembership(client, room); + const status = await shieldStatusForRoom(client, room); expect(status).toEqual(result); }); @@ -120,7 +120,7 @@ describe("shieldStatusForMembership self-trust behaviour", function() { roomId: dm ? "DM" : "other", getEncryptionTargetMembers: () => ["@self:localhost", "@FF:h"].map((userId) => ({userId})), }; - const status = await shieldStatusForMembership(client, room); + const status = await shieldStatusForRoom(client, room); expect(status).toEqual(result); }); }); @@ -140,7 +140,7 @@ describe("shieldStatusForMembership other-trust behaviour", function() { roomId: dm ? "DM" : "other", getEncryptionTargetMembers: () => ["@self:localhost", "@TF:h"].map((userId) => ({userId})), }; - const status = await shieldStatusForMembership(client, room); + const status = await shieldStatusForRoom(client, room); expect(status).toEqual(result); }); @@ -152,7 +152,7 @@ describe("shieldStatusForMembership other-trust behaviour", function() { roomId: dm ? "DM" : "other", getEncryptionTargetMembers: () => ["@self:localhost", "@TF:h", "@TT: h"].map((userId) => ({userId})), }; - const status = await shieldStatusForMembership(client, room); + const status = await shieldStatusForRoom(client, room); expect(status).toEqual(result); }); @@ -164,7 +164,7 @@ describe("shieldStatusForMembership other-trust behaviour", function() { roomId: dm ? "DM" : "other", getEncryptionTargetMembers: () => ["@self:localhost", "@FF:h", "@FT: h"].map((userId) => ({userId})), }; - const status = await shieldStatusForMembership(client, room); + const status = await shieldStatusForRoom(client, room); expect(status).toEqual(result); }); }); From d369695e2229dc270bcaf4ba7a4d991dea5c3cc9 Mon Sep 17 00:00:00 2001 From: RiotRobot Date: Mon, 30 Mar 2020 13:31:42 +0100 Subject: [PATCH 24/37] Upgrade matrix-js-sdk to 5.2.0 --- package.json | 2 +- yarn.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index 7579cab714..ce3ebea03f 100644 --- a/package.json +++ b/package.json @@ -79,7 +79,7 @@ "is-ip": "^2.0.0", "linkifyjs": "^2.1.6", "lodash": "^4.17.14", - "matrix-js-sdk": "5.2.0-rc.1", + "matrix-js-sdk": "5.2.0", "minimist": "^1.2.0", "pako": "^1.0.5", "png-chunks-extract": "^1.0.0", diff --git a/yarn.lock b/yarn.lock index 04dcab02ed..bb6c69cb2c 100644 --- a/yarn.lock +++ b/yarn.lock @@ -5689,10 +5689,10 @@ mathml-tag-names@^2.0.1: resolved "https://registry.yarnpkg.com/mathml-tag-names/-/mathml-tag-names-2.1.3.tgz#4ddadd67308e780cf16a47685878ee27b736a0a3" integrity sha512-APMBEanjybaPzUrfqU0IMU5I0AswKMH7k8OTLs0vvV4KZpExkTkY87nR/zpbuTPj+gARop7aGUbl11pnDfW6xg== -matrix-js-sdk@5.2.0-rc.1: - version "5.2.0-rc.1" - resolved "https://registry.yarnpkg.com/matrix-js-sdk/-/matrix-js-sdk-5.2.0-rc.1.tgz#014239eb713ea3b648b7a573785d01edff1efd03" - integrity sha512-Jv/0kyZEtkfrD6mlq3g2YoFI2+eOBFOz5D186jJAvFg1W7UaQ5gn6iualR+2AKa1AIk2AT6lDcgPb1djZ7/3Vw== +matrix-js-sdk@5.2.0: + version "5.2.0" + resolved "https://registry.yarnpkg.com/matrix-js-sdk/-/matrix-js-sdk-5.2.0.tgz#f213fd7671538a57c6d7e0665a2178ab23b950da" + integrity sha512-IscXYNx+k7wq5fuwsvKlXSI6Z1/nQ7TBI8AkStHJOAR8rz1DRoxICLFJtWzpOUSrgQuSaUYpOm4+6hS6IVlmtA== dependencies: "@babel/runtime" "^7.8.3" another-json "^0.2.0" From af1446e0ff87e73d4437d22f863e8cc3320d0feb Mon Sep 17 00:00:00 2001 From: RiotRobot Date: Mon, 30 Mar 2020 13:41:02 +0100 Subject: [PATCH 25/37] Prepare changelog for v2.3.0 --- CHANGELOG.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 378ba6f1d1..02c085d0b5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,9 @@ +Changes in [2.3.0](https://github.com/matrix-org/matrix-react-sdk/releases/tag/v2.3.0) (2020-03-30) +=================================================================================================== +[Full Changelog](https://github.com/matrix-org/matrix-react-sdk/compare/v2.3.0-rc.1...v2.3.0) + + * Upgrade JS SDK to 5.2.0 + Changes in [2.3.0-rc.1](https://github.com/matrix-org/matrix-react-sdk/releases/tag/v2.3.0-rc.1) (2020-03-26) ============================================================================================================= [Full Changelog](https://github.com/matrix-org/matrix-react-sdk/compare/v2.2.3...v2.3.0-rc.1) From e32e9cec06ca7f9a91da6aac33604b6e6cdec3e8 Mon Sep 17 00:00:00 2001 From: RiotRobot Date: Mon, 30 Mar 2020 13:41:02 +0100 Subject: [PATCH 26/37] v2.3.0 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index ce3ebea03f..6e3b4e912f 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "matrix-react-sdk", - "version": "2.3.0-rc.1", + "version": "2.3.0", "description": "SDK for matrix.org using React", "author": "matrix.org", "repository": { From 78fd8e4569096043b22210821d20e085802bbcff Mon Sep 17 00:00:00 2001 From: RiotRobot Date: Mon, 30 Mar 2020 13:42:52 +0100 Subject: [PATCH 27/37] Reset matrix-js-sdk back to develop branch --- package.json | 2 +- yarn.lock | 5 ++--- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/package.json b/package.json index 6e3b4e912f..7001b1cb21 100644 --- a/package.json +++ b/package.json @@ -79,7 +79,7 @@ "is-ip": "^2.0.0", "linkifyjs": "^2.1.6", "lodash": "^4.17.14", - "matrix-js-sdk": "5.2.0", + "matrix-js-sdk": "github:matrix-org/matrix-js-sdk#develop", "minimist": "^1.2.0", "pako": "^1.0.5", "png-chunks-extract": "^1.0.0", diff --git a/yarn.lock b/yarn.lock index bb6c69cb2c..c5fc8268a1 100644 --- a/yarn.lock +++ b/yarn.lock @@ -5689,10 +5689,9 @@ mathml-tag-names@^2.0.1: resolved "https://registry.yarnpkg.com/mathml-tag-names/-/mathml-tag-names-2.1.3.tgz#4ddadd67308e780cf16a47685878ee27b736a0a3" integrity sha512-APMBEanjybaPzUrfqU0IMU5I0AswKMH7k8OTLs0vvV4KZpExkTkY87nR/zpbuTPj+gARop7aGUbl11pnDfW6xg== -matrix-js-sdk@5.2.0: +"matrix-js-sdk@github:matrix-org/matrix-js-sdk#develop": version "5.2.0" - resolved "https://registry.yarnpkg.com/matrix-js-sdk/-/matrix-js-sdk-5.2.0.tgz#f213fd7671538a57c6d7e0665a2178ab23b950da" - integrity sha512-IscXYNx+k7wq5fuwsvKlXSI6Z1/nQ7TBI8AkStHJOAR8rz1DRoxICLFJtWzpOUSrgQuSaUYpOm4+6hS6IVlmtA== + resolved "https://codeload.github.com/matrix-org/matrix-js-sdk/tar.gz/223d37ffce674a23ca73702f04b9ba31cfd84196" dependencies: "@babel/runtime" "^7.8.3" another-json "^0.2.0" From 4371006c58b4565de1ef29d8d591333967fdcf23 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Damir=20Jeli=C4=87?= Date: Mon, 30 Mar 2020 14:32:35 +0200 Subject: [PATCH 28/37] EventIndex: Better logging on how many events are added. This adds a bit more info to how many events are added, how many skipped and if they are skipped because they are undecryptable. --- src/indexing/EventIndex.js | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/indexing/EventIndex.js b/src/indexing/EventIndex.js index 9e27451a78..65e536b4a1 100644 --- a/src/indexing/EventIndex.js +++ b/src/indexing/EventIndex.js @@ -469,6 +469,9 @@ export default class EventIndex extends EventEmitter { // decryption keys, do we want to retry this checkpoint at a later // stage? const filteredEvents = matrixEvents.filter(this.isValidEvent); + const undecryptableEvents = matrixEvents.filter((ev) => { + return ev.isDecryptionFailure(); + }); // Collect the redaction events so we can delete the redacted events // from the index. @@ -503,7 +506,10 @@ export default class EventIndex extends EventEmitter { console.log( "EventIndex: Crawled room", client.getRoom(checkpoint.roomId).name, - "and fetched", events.length, "events.", + "and fetched total", matrixEvents.length, "events of which", + events.length, "are being added,", redactionEvents.length, + "are redacted,", matrixEvents.length - events.length, + "are being skipped, undecryptable", undecryptableEvents.length ); try { From 836b348bff796dae1d56f2f19ea08dd258636333 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Damir=20Jeli=C4=87?= Date: Mon, 30 Mar 2020 14:39:01 +0200 Subject: [PATCH 29/37] EventIndex: Add a trailing comma. --- src/indexing/EventIndex.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/indexing/EventIndex.js b/src/indexing/EventIndex.js index 65e536b4a1..14257af014 100644 --- a/src/indexing/EventIndex.js +++ b/src/indexing/EventIndex.js @@ -509,7 +509,7 @@ export default class EventIndex extends EventEmitter { "and fetched total", matrixEvents.length, "events of which", events.length, "are being added,", redactionEvents.length, "are redacted,", matrixEvents.length - events.length, - "are being skipped, undecryptable", undecryptableEvents.length + "are being skipped, undecryptable", undecryptableEvents.length, ); try { From b53b5cc45de7d70b8686246f2c8037845b1ba2a1 Mon Sep 17 00:00:00 2001 From: "J. Ryan Stinnett" Date: Mon, 30 Mar 2020 15:24:43 +0100 Subject: [PATCH 30/37] Add wasCrossSigningVerified in test --- test/utils/ShieldUtils-test.js | 1 + 1 file changed, 1 insertion(+) diff --git a/test/utils/ShieldUtils-test.js b/test/utils/ShieldUtils-test.js index 949f0ed42b..66dfab4234 100644 --- a/test/utils/ShieldUtils-test.js +++ b/test/utils/ShieldUtils-test.js @@ -6,6 +6,7 @@ function mkClient(selfTrust) { getUserId: () => "@self:localhost", checkUserTrust: (userId) => ({ isCrossSigningVerified: () => userId[1] == "T", + wasCrossSigningVerified: () => userId[1] == "T", }), checkDeviceTrust: (userId, deviceId) => ({ isVerified: () => userId === "@self:localhost" ? selfTrust : userId[2] == "T", From 520b4c3e65331913647ceb3fec04333478267174 Mon Sep 17 00:00:00 2001 From: "J. Ryan Stinnett" Date: Mon, 30 Mar 2020 16:33:16 +0100 Subject: [PATCH 31/37] Add tests for was verified case --- test/utils/ShieldUtils-test.js | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/test/utils/ShieldUtils-test.js b/test/utils/ShieldUtils-test.js index 66dfab4234..5f676579fa 100644 --- a/test/utils/ShieldUtils-test.js +++ b/test/utils/ShieldUtils-test.js @@ -6,7 +6,7 @@ function mkClient(selfTrust) { getUserId: () => "@self:localhost", checkUserTrust: (userId) => ({ isCrossSigningVerified: () => userId[1] == "T", - wasCrossSigningVerified: () => userId[1] == "T", + wasCrossSigningVerified: () => userId[1] == "T" || userId[1] == "W", }), checkDeviceTrust: (userId, deviceId) => ({ isVerified: () => userId === "@self:localhost" ? selfTrust : userId[2] == "T", @@ -151,7 +151,7 @@ describe("shieldStatusForMembership other-trust behaviour", function() { const client = mkClient(true); const room = { roomId: dm ? "DM" : "other", - getEncryptionTargetMembers: () => ["@self:localhost", "@TF:h", "@TT: h"].map((userId) => ({userId})), + getEncryptionTargetMembers: () => ["@self:localhost", "@TF:h", "@TT:h"].map((userId) => ({userId})), }; const status = await shieldStatusForRoom(client, room); expect(status).toEqual(result); @@ -163,7 +163,19 @@ describe("shieldStatusForMembership other-trust behaviour", function() { const client = mkClient(true); const room = { roomId: dm ? "DM" : "other", - getEncryptionTargetMembers: () => ["@self:localhost", "@FF:h", "@FT: h"].map((userId) => ({userId})), + getEncryptionTargetMembers: () => ["@self:localhost", "@FF:h", "@FT:h"].map((userId) => ({userId})), + }; + const status = await shieldStatusForRoom(client, room); + expect(status).toEqual(result); + }); + + it.each( + [["warning", true], ["warning", false]], + )("2 was verified: returns '%s', DM = %s", async (result, dm) => { + const client = mkClient(true); + const room = { + roomId: dm ? "DM" : "other", + getEncryptionTargetMembers: () => ["@self:localhost", "@WF:h", "@FT:h"].map((userId) => ({userId})), }; const status = await shieldStatusForRoom(client, room); expect(status).toEqual(result); From ca5d54031162d19379ddec255e8eeeff33d2b750 Mon Sep 17 00:00:00 2001 From: Travis Ralston Date: Mon, 30 Mar 2020 10:40:26 -0600 Subject: [PATCH 32/37] Remove underscore from Jitsi conference names Fixes https://github.com/vector-im/riot-web/issues/12929 Note: we don't need this to fix conferences in our hosted instance (riot.im or modular.im), but it is a common thing for self-hosters, including sometimes ourselves, to accidentally make mistakes on. --- src/CallHandler.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/CallHandler.js b/src/CallHandler.js index 362db939a3..8284e788b4 100644 --- a/src/CallHandler.js +++ b/src/CallHandler.js @@ -430,7 +430,7 @@ async function _startCallApp(roomId, type) { return; } - const confId = `JitsiConference_${generateHumanReadableId()}`; + const confId = `JitsiConference${generateHumanReadableId()}`; const jitsiDomain = SdkConfig.get()['jitsi']['preferredDomain']; let widgetUrl = WidgetUtils.getLocalJitsiWrapperUrl(); From 147e7bc57ea5332fdf25129599773c3ed4e974fa Mon Sep 17 00:00:00 2001 From: Michael Telatynski <7t3chguy@gmail.com> Date: Mon, 30 Mar 2020 18:42:47 +0100 Subject: [PATCH 33/37] Field: mark id as optional in propTypes Signed-off-by: Michael Telatynski <7t3chguy@gmail.com> --- src/components/views/elements/Field.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/views/elements/Field.js b/src/components/views/elements/Field.js index 797c83bc06..2ebb90da26 100644 --- a/src/components/views/elements/Field.js +++ b/src/components/views/elements/Field.js @@ -32,7 +32,7 @@ function getId() { export default class Field extends React.PureComponent { static propTypes = { // The field's ID, which binds the input and label together. Immutable. - id: PropTypes.string.isRequired, + id: PropTypes.string, // The element to create. Defaults to "input". // To define options for a select, use element: PropTypes.oneOf(["input", "select", "textarea"]), From dd4331cd18ee048dd684bd879dd0ddc4a83e1f0a Mon Sep 17 00:00:00 2001 From: waylon531 Date: Sun, 29 Mar 2020 12:45:06 -0700 Subject: [PATCH 34/37] Added the /html command This command lets you send html messages through riot. This is incredibly useful for doing advanced formatting not supported by markdown and lets riot support even more html tags. Signed-off-by: Waylon Cude --- src/SlashCommands.js | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/SlashCommands.js b/src/SlashCommands.js index d306978f78..72ca4b1566 100644 --- a/src/SlashCommands.js +++ b/src/SlashCommands.js @@ -128,6 +128,15 @@ export const CommandMap = { }, category: CommandCategories.messages, }), + html: new Command({ + name: 'html', + args: '', + description: _td('Sends a message as html, without interpreting it as markdown'), + runFn: function(roomId, messages) { + return success(MatrixClientPeg.get().sendHtmlMessage(roomId, messages, messages)); + }, + category: CommandCategories.messages, + }), ddg: new Command({ name: 'ddg', args: '', From 9cf82d8743846efbaf1f40914cf24ffbbcb4f417 Mon Sep 17 00:00:00 2001 From: waylon531 Date: Sun, 29 Mar 2020 13:10:53 -0700 Subject: [PATCH 35/37] Updated strings I added a new string for the /html command and had to regerate strings for i18 Signed-off-by: Waylon Cude --- src/i18n/strings/en_EN.json | 1 + 1 file changed, 1 insertion(+) diff --git a/src/i18n/strings/en_EN.json b/src/i18n/strings/en_EN.json index a6e195aa16..3962899223 100644 --- a/src/i18n/strings/en_EN.json +++ b/src/i18n/strings/en_EN.json @@ -153,6 +153,7 @@ "Usage": "Usage", "Prepends ¯\\_(ツ)_/¯ to a plain-text message": "Prepends ¯\\_(ツ)_/¯ to a plain-text message", "Sends a message as plain text, without interpreting it as markdown": "Sends a message as plain text, without interpreting it as markdown", + "Sends a message as html, without interpreting it as markdown": "Sends a message as html, without interpreting it as markdown", "Searches DuckDuckGo for results": "Searches DuckDuckGo for results", "/ddg is not a command": "/ddg is not a command", "To use it, just wait for autocomplete results to load and tab through them.": "To use it, just wait for autocomplete results to load and tab through them.", From 690b5945d01134d8fd88672432a93befb03ce710 Mon Sep 17 00:00:00 2001 From: "J. Ryan Stinnett" Date: Mon, 30 Mar 2020 21:40:09 +0100 Subject: [PATCH 36/37] Pass new secret storage key to bootstrap path This passes the newly created secret storage key down to the bootstrap path for temporary caching to avoid prompting the user for it again in the later stages of bootstrapping. Fixes https://github.com/vector-im/riot-web/issues/12867 --- .../CreateSecretStorageDialog.js | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) diff --git a/src/async-components/views/dialogs/secretstorage/CreateSecretStorageDialog.js b/src/async-components/views/dialogs/secretstorage/CreateSecretStorageDialog.js index 78e750b817..1149f230ef 100644 --- a/src/async-components/views/dialogs/secretstorage/CreateSecretStorageDialog.js +++ b/src/async-components/views/dialogs/secretstorage/CreateSecretStorageDialog.js @@ -69,6 +69,7 @@ export default class CreateSecretStorageDialog extends React.PureComponent { this._keyInfo = null; this._encodedRecoveryKey = null; + this._recoveryKey = null; this._recoveryKeyNode = null; this._setZxcvbnResultTimeout = null; @@ -234,14 +235,22 @@ export default class CreateSecretStorageDialog extends React.PureComponent { if (force) { await cli.bootstrapSecretStorage({ authUploadDeviceSigningKeys: this._doBootstrapUIAuth, - createSecretStorageKey: async () => this._keyInfo, + createSecretStorageKey: async () => [ + this._keyInfo, + this._encodedRecoveryKey, + this._recoveryKey, + ], setupNewKeyBackup: true, setupNewSecretStorage: true, }); } else { await cli.bootstrapSecretStorage({ authUploadDeviceSigningKeys: this._doBootstrapUIAuth, - createSecretStorageKey: async () => this._keyInfo, + createSecretStorageKey: async () => [ + this._keyInfo, + this._encodedRecoveryKey, + this._recoveryKey, + ], keyBackupInfo: this.state.backupInfo, setupNewKeyBackup: !this.state.backupInfo && this.state.useKeyBackup, getKeyBackupPassphrase: promptForBackupPassphrase, @@ -299,10 +308,11 @@ export default class CreateSecretStorageDialog extends React.PureComponent { } _onSkipPassPhraseClick = async () => { - const [keyInfo, encodedRecoveryKey] = + const [keyInfo, encodedRecoveryKey, recoveryKey] = await MatrixClientPeg.get().createRecoveryKeyFromPassphrase(); this._keyInfo = keyInfo; this._encodedRecoveryKey = encodedRecoveryKey; + this._recoveryKey = recoveryKey; this.setState({ copied: false, downloaded: false, @@ -335,10 +345,11 @@ export default class CreateSecretStorageDialog extends React.PureComponent { if (this.state.passPhrase !== this.state.passPhraseConfirm) return; - const [keyInfo, encodedRecoveryKey] = + const [keyInfo, encodedRecoveryKey, recoveryKey] = await MatrixClientPeg.get().createRecoveryKeyFromPassphrase(this.state.passPhrase); this._keyInfo = keyInfo; this._encodedRecoveryKey = encodedRecoveryKey; + this._recoveryKey = recoveryKey; this.setState({ copied: false, downloaded: false, From 24c09cc4c8e647db9c6bfe69a681606cce4a3e68 Mon Sep 17 00:00:00 2001 From: "J. Ryan Stinnett" Date: Tue, 31 Mar 2020 10:45:53 +0100 Subject: [PATCH 37/37] Convert secret storage key creation to object --- .../CreateSecretStorageDialog.js | 28 ++++--------------- 1 file changed, 6 insertions(+), 22 deletions(-) diff --git a/src/async-components/views/dialogs/secretstorage/CreateSecretStorageDialog.js b/src/async-components/views/dialogs/secretstorage/CreateSecretStorageDialog.js index 1149f230ef..01a2856df0 100644 --- a/src/async-components/views/dialogs/secretstorage/CreateSecretStorageDialog.js +++ b/src/async-components/views/dialogs/secretstorage/CreateSecretStorageDialog.js @@ -67,8 +67,6 @@ export default class CreateSecretStorageDialog extends React.PureComponent { constructor(props) { super(props); - this._keyInfo = null; - this._encodedRecoveryKey = null; this._recoveryKey = null; this._recoveryKeyNode = null; this._setZxcvbnResultTimeout = null; @@ -181,7 +179,7 @@ export default class CreateSecretStorageDialog extends React.PureComponent { } _onDownloadClick = () => { - const blob = new Blob([this._encodedRecoveryKey], { + const blob = new Blob([this._recoveryKey.encodedPrivateKey], { type: 'text/plain;charset=us-ascii', }); FileSaver.saveAs(blob, 'recovery-key.txt'); @@ -235,22 +233,14 @@ export default class CreateSecretStorageDialog extends React.PureComponent { if (force) { await cli.bootstrapSecretStorage({ authUploadDeviceSigningKeys: this._doBootstrapUIAuth, - createSecretStorageKey: async () => [ - this._keyInfo, - this._encodedRecoveryKey, - this._recoveryKey, - ], + createSecretStorageKey: async () => this._recoveryKey, setupNewKeyBackup: true, setupNewSecretStorage: true, }); } else { await cli.bootstrapSecretStorage({ authUploadDeviceSigningKeys: this._doBootstrapUIAuth, - createSecretStorageKey: async () => [ - this._keyInfo, - this._encodedRecoveryKey, - this._recoveryKey, - ], + createSecretStorageKey: async () => this._recoveryKey, keyBackupInfo: this.state.backupInfo, setupNewKeyBackup: !this.state.backupInfo && this.state.useKeyBackup, getKeyBackupPassphrase: promptForBackupPassphrase, @@ -308,11 +298,8 @@ export default class CreateSecretStorageDialog extends React.PureComponent { } _onSkipPassPhraseClick = async () => { - const [keyInfo, encodedRecoveryKey, recoveryKey] = + this._recoveryKey = await MatrixClientPeg.get().createRecoveryKeyFromPassphrase(); - this._keyInfo = keyInfo; - this._encodedRecoveryKey = encodedRecoveryKey; - this._recoveryKey = recoveryKey; this.setState({ copied: false, downloaded: false, @@ -345,11 +332,8 @@ export default class CreateSecretStorageDialog extends React.PureComponent { if (this.state.passPhrase !== this.state.passPhraseConfirm) return; - const [keyInfo, encodedRecoveryKey, recoveryKey] = + this._recoveryKey = await MatrixClientPeg.get().createRecoveryKeyFromPassphrase(this.state.passPhrase); - this._keyInfo = keyInfo; - this._encodedRecoveryKey = encodedRecoveryKey; - this._recoveryKey = recoveryKey; this.setState({ copied: false, downloaded: false, @@ -624,7 +608,7 @@ export default class CreateSecretStorageDialog extends React.PureComponent {
- {this._encodedRecoveryKey} + {this._recoveryKey.encodedPrivateKey}