diff --git a/src/async-components/views/dialogs/keybackup/CreateKeyBackupDialog.js b/src/async-components/views/dialogs/keybackup/CreateKeyBackupDialog.js
index f89fb17448..3a480a2579 100644
--- a/src/async-components/views/dialogs/keybackup/CreateKeyBackupDialog.js
+++ b/src/async-components/views/dialogs/keybackup/CreateKeyBackupDialog.js
@@ -53,7 +53,6 @@ function selectText(target) {
*/
export default class CreateKeyBackupDialog extends React.PureComponent {
static propTypes = {
- secureSecretStorage: PropTypes.bool,
onFinished: PropTypes.func.isRequired,
}
@@ -65,7 +64,7 @@ export default class CreateKeyBackupDialog extends React.PureComponent {
this._setZxcvbnResultTimeout = null;
this.state = {
- secureSecretStorage: props.secureSecretStorage,
+ secureSecretStorage: null,
phase: PHASE_PASSPHRASE,
passPhrase: '',
passPhraseConfirm: '',
@@ -73,23 +72,20 @@ export default class CreateKeyBackupDialog extends React.PureComponent {
downloaded: false,
zxcvbnResult: null,
};
-
- if (this.state.secureSecretStorage === undefined) {
- this.state.secureSecretStorage =
- SettingsStore.isFeatureEnabled("feature_cross_signing");
- }
-
- // If we're using secret storage, skip ahead to the backing up step, as
- // `accessSecretStorage` will handle passphrases as needed.
- if (this.state.secureSecretStorage) {
- this.state.phase = PHASE_BACKINGUP;
- }
}
- componentDidMount() {
+ async componentDidMount() {
+ const cli = MatrixClientPeg.get();
+ const secureSecretStorage = (
+ SettingsStore.isFeatureEnabled("feature_cross_signing") &&
+ await cli.doesServerSupportUnstableFeature("org.matrix.e2e_cross_signing")
+ );
+ this.setState({ secureSecretStorage });
+
// If we're using secret storage, skip ahead to the backing up step, as
// `accessSecretStorage` will handle passphrases as needed.
- if (this.state.secureSecretStorage) {
+ if (secureSecretStorage) {
+ this.setState({ phase: PHASE_BACKINGUP });
this._createBackup();
}
}
diff --git a/src/components/views/right_panel/UserInfo.js b/src/components/views/right_panel/UserInfo.js
index 1174f45640..44770d9ccc 100644
--- a/src/components/views/right_panel/UserInfo.js
+++ b/src/components/views/right_panel/UserInfo.js
@@ -42,6 +42,7 @@ import {textualPowerLevel} from '../../../Roles';
import MatrixClientContext from "../../../contexts/MatrixClientContext";
import {RIGHT_PANEL_PHASES} from "../../../stores/RightPanelStorePhases";
import EncryptionPanel from "./EncryptionPanel";
+import { useAsyncMemo } from '../../../hooks/useAsyncMemo';
const _disambiguateDevices = (devices) => {
const names = Object.create(null);
@@ -916,6 +917,12 @@ const useIsSynapseAdmin = (cli) => {
return isAdmin;
};
+const useHomeserverSupportsCrossSigning = (cli) => {
+ return useAsyncMemo(async () => {
+ return cli.doesServerSupportUnstableFeature("org.matrix.e2e_cross_signing");
+ }, [cli], false);
+};
+
function useRoomPermissions(cli, room, user) {
const [roomPermissions, setRoomPermissions] = useState({
// modifyLevelMax is the max PL we can set this user to, typically min(their PL, our PL) && canSetPL
@@ -1315,19 +1322,23 @@ const BasicUserInfo = ({room, member, groupId, devices, isRoomEncrypted}) => {
text = _t("Messages in this room are end-to-end encrypted.");
}
- const userTrust = cli.checkUserTrust(member.userId);
- const userVerified = SettingsStore.isFeatureEnabled("feature_cross_signing") ?
- userTrust.isCrossSigningVerified() :
- userTrust.isVerified();
- const isMe = member.userId === cli.getUserId();
-
let verifyButton;
- if (isRoomEncrypted && !userVerified && !isMe) {
- verifyButton = (
- verifyUser(member)}>
- {_t("Verify")}
-
- );
+ const homeserverSupportsCrossSigning = useHomeserverSupportsCrossSigning(cli);
+ if (
+ SettingsStore.isFeatureEnabled("feature_cross_signing") &&
+ homeserverSupportsCrossSigning
+ ) {
+ const userTrust = cli.checkUserTrust(member.userId);
+ const userVerified = userTrust.isCrossSigningVerified();
+ const isMe = member.userId === cli.getUserId();
+
+ if (isRoomEncrypted && !userVerified && !isMe) {
+ verifyButton = (
+ verifyUser(member)}>
+ {_t("Verify")}
+
+ );
+ }
}
let devicesSection;
diff --git a/src/components/views/settings/CrossSigningPanel.js b/src/components/views/settings/CrossSigningPanel.js
index 6e69227844..aba2d03ad2 100644
--- a/src/components/views/settings/CrossSigningPanel.js
+++ b/src/components/views/settings/CrossSigningPanel.js
@@ -72,11 +72,14 @@ export default class CrossSigningPanel extends React.PureComponent {
const crossSigningPublicKeysOnDevice = crossSigning.getId();
const crossSigningPrivateKeysInStorage = await crossSigning.isStoredInSecretStorage(secretStorage);
const secretStorageKeyInAccount = await secretStorage.hasKey();
+ const homeserverSupportsCrossSigning =
+ await cli.doesServerSupportUnstableFeature("org.matrix.e2e_cross_signing");
this.setState({
crossSigningPublicKeysOnDevice,
crossSigningPrivateKeysInStorage,
secretStorageKeyInAccount,
+ homeserverSupportsCrossSigning,
});
}
@@ -120,6 +123,7 @@ export default class CrossSigningPanel extends React.PureComponent {
crossSigningPublicKeysOnDevice,
crossSigningPrivateKeysInStorage,
secretStorageKeyInAccount,
+ homeserverSupportsCrossSigning,
} = this.state;
let errorSection;
@@ -127,13 +131,19 @@ export default class CrossSigningPanel extends React.PureComponent {
errorSection =
{error.toString()}
;
}
- const enabled = (
+ // Whether the various keys exist on your account (but not necessarily
+ // on this device).
+ const enabledForAccount = (
crossSigningPrivateKeysInStorage &&
secretStorageKeyInAccount
);
let summarisedStatus;
- if (enabled && crossSigningPublicKeysOnDevice) {
+ if (!homeserverSupportsCrossSigning) {
+ summarisedStatus = {_t(
+ "Your homeserver does not support cross-signing.",
+ )}
;
+ } else if (enabledForAccount && crossSigningPublicKeysOnDevice) {
summarisedStatus = ✅ {_t(
"Cross-signing and secret storage are enabled.",
)}
;
@@ -149,18 +159,18 @@ export default class CrossSigningPanel extends React.PureComponent {
}
let bootstrapButton;
- if (!enabled) {
- bootstrapButton =
-
- {_t("Bootstrap cross-signing and secret storage")}
-
-
;
- } else {
- bootstrapButton =
+ if (enabledForAccount) {
+ bootstrapButton = (
{_t("Reset cross-signing and secret storage")}
-
;
+ );
+ } else if (!enabledForAccount && homeserverSupportsCrossSigning) {
+ bootstrapButton = (
+
+ {_t("Bootstrap cross-signing and secret storage")}
+
+ );
}
return (
@@ -181,10 +191,16 @@ export default class CrossSigningPanel extends React.PureComponent {
{_t("Secret storage public key:")} |
{secretStorageKeyInAccount ? _t("in account data") : _t("not found")} |
-
+
+ {_t("Homeserver feature support:")} |
+ {homeserverSupportsCrossSigning ? _t("exists") : _t("not found")} |
+
+
{errorSection}
- {bootstrapButton}
+
+ {bootstrapButton}
+
);
}
diff --git a/src/components/views/settings/KeyBackupPanel.js b/src/components/views/settings/KeyBackupPanel.js
index f3fe171e63..73be2bad9f 100644
--- a/src/components/views/settings/KeyBackupPanel.js
+++ b/src/components/views/settings/KeyBackupPanel.js
@@ -127,7 +127,6 @@ export default class KeyBackupPanel extends React.PureComponent {
Modal.createTrackedDialogAsync('Key Backup', 'Key Backup',
import('../../../async-components/views/dialogs/keybackup/CreateKeyBackupDialog'),
{
- secureSecretStorage: SettingsStore.isFeatureEnabled("feature_cross_signing"),
onFinished: () => {
this._loadBackupStatus();
},
diff --git a/src/hooks/useAsyncMemo.js b/src/hooks/useAsyncMemo.js
new file mode 100644
index 0000000000..ef7d256b04
--- /dev/null
+++ b/src/hooks/useAsyncMemo.js
@@ -0,0 +1,25 @@
+/*
+Copyright 2020 The Matrix.org Foundation C.I.C.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+import { useState, useEffect } from 'react';
+
+export const useAsyncMemo = (fn, deps, initialValue) => {
+ const [value, setValue] = useState(initialValue);
+ useEffect(() => {
+ fn().then(setValue);
+ }, deps); // eslint-disable-line react-hooks/exhaustive-deps
+ return value;
+};
diff --git a/src/i18n/strings/en_EN.json b/src/i18n/strings/en_EN.json
index 82eb660d9d..1d030f5118 100644
--- a/src/i18n/strings/en_EN.json
+++ b/src/i18n/strings/en_EN.json
@@ -562,11 +562,12 @@
"New Password": "New Password",
"Confirm password": "Confirm password",
"Change Password": "Change Password",
+ "Your homeserver does not support cross-signing.": "Your homeserver does not support cross-signing.",
"Cross-signing and secret storage are enabled.": "Cross-signing and secret storage are enabled.",
"Your account has a cross-signing identity in secret storage, but it is not yet trusted by this session.": "Your account has a cross-signing identity in secret storage, but it is not yet trusted by this session.",
"Cross-signing and secret storage are not yet set up.": "Cross-signing and secret storage are not yet set up.",
- "Bootstrap cross-signing and secret storage": "Bootstrap cross-signing and secret storage",
"Reset cross-signing and secret storage": "Reset cross-signing and secret storage",
+ "Bootstrap cross-signing and secret storage": "Bootstrap cross-signing and secret storage",
"Cross-signing public keys:": "Cross-signing public keys:",
"in memory": "in memory",
"not found": "not found",
@@ -574,6 +575,8 @@
"in secret storage": "in secret storage",
"Secret storage public key:": "Secret storage public key:",
"in account data": "in account data",
+ "Homeserver feature support:": "Homeserver feature support:",
+ "exists": "exists",
"Your homeserver does not support session management.": "Your homeserver does not support session management.",
"Unable to load session list": "Unable to load session list",
"Authentication": "Authentication",