diff --git a/res/css/_common.scss b/res/css/_common.scss
index 9123e5ba8d..11e04f5dc0 100644
--- a/res/css/_common.scss
+++ b/res/css/_common.scss
@@ -262,6 +262,11 @@ textarea {
opacity: 0.7;
}
+.mx_linkButton {
+ cursor: pointer;
+ color: $accent-color;
+}
+
.mx_Dialog_title {
min-height: 16px;
padding-top: 40px;
diff --git a/res/css/_components.scss b/res/css/_components.scss
index a09f895d5f..083071ef6c 100644
--- a/res/css/_components.scss
+++ b/res/css/_components.scss
@@ -33,17 +33,21 @@
@import "./views/dialogs/_ChatInviteDialog.scss";
@import "./views/dialogs/_ConfirmUserActionDialog.scss";
@import "./views/dialogs/_CreateGroupDialog.scss";
+@import "./views/dialogs/_CreateKeyBackupDialog.scss";
@import "./views/dialogs/_CreateRoomDialog.scss";
@import "./views/dialogs/_DeactivateAccountDialog.scss";
@import "./views/dialogs/_DevtoolsDialog.scss";
@import "./views/dialogs/_EncryptedEventDialog.scss";
@import "./views/dialogs/_GroupAddressPicker.scss";
+@import "./views/dialogs/_RestoreKeyBackupDialog.scss";
@import "./views/dialogs/_RoomUpgradeDialog.scss";
@import "./views/dialogs/_SetEmailDialog.scss";
@import "./views/dialogs/_SetMxIdDialog.scss";
@import "./views/dialogs/_SetPasswordDialog.scss";
@import "./views/dialogs/_ShareDialog.scss";
@import "./views/dialogs/_UnknownDeviceDialog.scss";
+@import "./views/dialogs/keybackup/_CreateKeyBackupDialog.scss";
+@import "./views/dialogs/keybackup/_RestoreKeyBackupDialog.scss";
@import "./views/directory/_NetworkDropdown.scss";
@import "./views/elements/_AccessibleButton.scss";
@import "./views/elements/_AddressSelector.scss";
@@ -107,6 +111,7 @@
@import "./views/rooms/_TopUnreadMessagesBar.scss";
@import "./views/settings/_DevicesPanel.scss";
@import "./views/settings/_IntegrationsManager.scss";
+@import "./views/settings/_KeyBackupPanel.scss";
@import "./views/settings/_Notifications.scss";
@import "./views/voip/_CallView.scss";
@import "./views/voip/_IncomingCallbox.scss";
diff --git a/res/css/views/dialogs/_CreateKeyBackupDialog.scss b/res/css/views/dialogs/_CreateKeyBackupDialog.scss
new file mode 100644
index 0000000000..a422cf858c
--- /dev/null
+++ b/res/css/views/dialogs/_CreateKeyBackupDialog.scss
@@ -0,0 +1,25 @@
+/*
+Copyright 2018 New Vector Ltd
+
+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.
+*/
+
+.mx_CreateKeyBackupDialog {
+ padding-right: 40px;
+}
+
+.mx_CreateKeyBackupDialog_recoveryKey {
+ padding: 20px;
+ color: $info-plinth-fg-color;
+ background-color: $info-plinth-bg-color;
+}
diff --git a/res/css/views/dialogs/_RestoreKeyBackupDialog.scss b/res/css/views/dialogs/_RestoreKeyBackupDialog.scss
new file mode 100644
index 0000000000..69e00c416a
--- /dev/null
+++ b/res/css/views/dialogs/_RestoreKeyBackupDialog.scss
@@ -0,0 +1,19 @@
+/*
+Copyright 2018 New Vector Ltd
+
+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.
+*/
+
+.mx_RestoreKeyBackupDialog_keyStatus {
+ height: 30px;
+}
diff --git a/res/css/views/dialogs/keybackup/_CreateKeyBackupDialog.scss b/res/css/views/dialogs/keybackup/_CreateKeyBackupDialog.scss
new file mode 100644
index 0000000000..507c89ace7
--- /dev/null
+++ b/res/css/views/dialogs/keybackup/_CreateKeyBackupDialog.scss
@@ -0,0 +1,39 @@
+/*
+Copyright 2018 New Vector Ltd
+
+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.
+*/
+
+.mx_CreateKeyBackupDialog_primaryContainer {
+ /*FIXME: plinth colour in new theme(s). background-color: $accent-color;*/
+ padding: 20px
+}
+
+.mx_CreateKeyBackupDialog_passPhraseInput {
+ width: 300px;
+ border: 1px solid $accent-color;
+ border-radius: 5px;
+ padding: 10px;
+}
+
+.mx_CreateKeyBackupDialog_passPhraseMatch {
+ float: right;
+}
+
+.mx_CreateKeyBackupDialog_recoveryKeyButtons {
+ float: right;
+}
+
+.mx_CreateKeyBackupDialog_recoveryKey {
+ width: 300px;
+}
diff --git a/res/css/views/dialogs/keybackup/_RestoreKeyBackupDialog.scss b/res/css/views/dialogs/keybackup/_RestoreKeyBackupDialog.scss
new file mode 100644
index 0000000000..612c921038
--- /dev/null
+++ b/res/css/views/dialogs/keybackup/_RestoreKeyBackupDialog.scss
@@ -0,0 +1,29 @@
+/*
+Copyright 2018 New Vector Ltd
+
+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.
+*/
+
+.mx_RestoreKeyBackupDialog_primaryContainer {
+ /*FIXME: plinth colour in new theme(s). background-color: $accent-color;*/
+ padding: 20px
+}
+
+.mx_RestoreKeyBackupDialog_passPhraseInput,
+.mx_RestoreKeyBackupDialog_recoveryKeyInput {
+ width: 300px;
+ border: 1px solid $accent-color;
+ border-radius: 5px;
+ padding: 10px;
+}
+
diff --git a/res/css/views/settings/_KeyBackupPanel.scss b/res/css/views/settings/_KeyBackupPanel.scss
new file mode 100644
index 0000000000..1bcc0ab10d
--- /dev/null
+++ b/res/css/views/settings/_KeyBackupPanel.scss
@@ -0,0 +1,32 @@
+/*
+Copyright 2018 New Vector Ltd
+
+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.
+*/
+
+.mx_KeyBackupPanel_sigValid, .mx_KeyBackupPanel_sigInvalid,
+.mx_KeyBackupPanel_deviceVerified, .mx_KeyBackupPanel_deviceNotVerified {
+ font-weight: bold;
+}
+
+.mx_KeyBackupPanel_sigValid, .mx_KeyBackupPanel_deviceVerified {
+ color: $e2e-verified-color;
+}
+
+.mx_KeyBackupPanel_sigInvalid, .mx_KeyBackupPanel_deviceNotVerified {
+ color: $e2e-warning-color;
+}
+
+.mx_KeyBackupPanel_deviceName {
+ font-style: italic;
+}
diff --git a/src/components/structures/MatrixChat.js b/src/components/structures/MatrixChat.js
index f3f188df81..4d7c71e3ef 100644
--- a/src/components/structures/MatrixChat.js
+++ b/src/components/structures/MatrixChat.js
@@ -1375,6 +1375,7 @@ export default React.createClass({
cli.on("crypto.roomKeyRequestCancellation", (req) => {
krh.handleKeyRequestCancellation(req);
});
+
cli.on("Room", (room) => {
if (MatrixClientPeg.get().isCryptoEnabled()) {
const blacklistEnabled = SettingsStore.getValueAt(
diff --git a/src/components/structures/UserSettings.js b/src/components/structures/UserSettings.js
index c02e482746..4c15b4ec27 100644
--- a/src/components/structures/UserSettings.js
+++ b/src/components/structures/UserSettings.js
@@ -737,6 +737,16 @@ module.exports = React.createClass({
);
}
+
+ let keyBackupSection;
+ if (SettingsStore.isFeatureEnabled("feature_keybackup")) {
+ const KeyBackupPanel = sdk.getComponent('views.settings.KeyBackupPanel');
+ keyBackupSection =
{_t(
+ "Type in your Recovery Passphrase to confirm you remember it. " +
+ "If it helps, add it to your password manager or store it " +
+ "somewhere safe.",
+ )}
+ {_t(
+ "Without setting up Secure Message Recovery, you won't be able to restore your " +
+ "encrypted message history if you log out or use another device.",
+ )}
+
+
+
+
;
+ },
+
+ _titleForPhase: function(phase) {
+ switch (phase) {
+ case PHASE_PASSPHRASE:
+ return _t('Create a Recovery Passphrase');
+ case PHASE_PASSPHRASE_CONFIRM:
+ return _t('Confirm Recovery Passphrase');
+ case PHASE_OPTOUT_CONFIRM:
+ return _t('Warning!');
+ case PHASE_SHOWKEY:
+ return _t('Recovery Key');
+ case PHASE_KEEPITSAFE:
+ return _t('Keep it safe');
+ case PHASE_BACKINGUP:
+ return _t('Backing up...');
+ default:
+ return _t("Create Key Backup");
+ }
+ },
+
+ render: function() {
+ const BaseDialog = sdk.getComponent('views.dialogs.BaseDialog');
+
+ let content;
+ if (this.state.error) {
+ const DialogButtons = sdk.getComponent('views.elements.DialogButtons');
+ content =
;
+ }
+ }
+}
diff --git a/src/i18n/strings/en_EN.json b/src/i18n/strings/en_EN.json
index 01c4926467..557ef62edf 100644
--- a/src/i18n/strings/en_EN.json
+++ b/src/i18n/strings/en_EN.json
@@ -225,6 +225,7 @@
"Failed to join room": "Failed to join room",
"Message Pinning": "Message Pinning",
"Increase performance by only loading room members on first view": "Increase performance by only loading room members on first view",
+ "Backup of encryption keys to server": "Backup of encryption keys to server",
"Disable Emoji suggestions while typing": "Disable Emoji suggestions while typing",
"Use compact timeline layout": "Use compact timeline layout",
"Hide removed messages": "Hide removed messages",
@@ -309,6 +310,24 @@
"Failed to set display name": "Failed to set display name",
"Disable Notifications": "Disable Notifications",
"Enable Notifications": "Enable Notifications",
+ "Delete Backup": "Delete Backup",
+ "Delete your backed up encryption keys from the server? You will no longer be able to use your recovery key to read encrypted message history": "Delete your backed up encryption keys from the server? You will no longer be able to use your recovery key to read encrypted message history",
+ "Delete backup": "Delete backup",
+ "Unable to load key backup status": "Unable to load key backup status",
+ "This device is uploading keys to this backup": "This device is uploading keys to this backup",
+ "This device is not uploading keys to this backup": "This device is not uploading keys to this backup",
+ "Backup has a valid signature from this device": "Backup has a valid signature from this device",
+ "Backup has a valid signature from verified device x": "Backup has a valid signature from verified device x",
+ "Backup has a valid signature from unverified device ": "Backup has a valid signature from unverified device ",
+ "Backup has an invalid signature from verified device ": "Backup has an invalid signature from verified device ",
+ "Backup has an invalid signature from unverified device ": "Backup has an invalid signature from unverified device ",
+ "Verify...": "Verify...",
+ "Backup is not signed by any of your devices": "Backup is not signed by any of your devices",
+ "Backup version: ": "Backup version: ",
+ "Algorithm: ": "Algorithm: ",
+ "Restore backup": "Restore backup",
+ "No backup is present": "No backup is present",
+ "Start a new backup": "Start a new backup",
"Error saving email notification preferences": "Error saving email notification preferences",
"An error occurred whilst saving your email notification preferences.": "An error occurred whilst saving your email notification preferences.",
"Keywords": "Keywords",
@@ -740,7 +759,6 @@
"Unblacklist": "Unblacklist",
"Blacklist": "Blacklist",
"Unverify": "Unverify",
- "Verify...": "Verify...",
"No results": "No results",
"Delete": "Delete",
"Communities": "Communities",
@@ -955,6 +973,55 @@
"Room contains unknown devices": "Room contains unknown devices",
"\"%(RoomName)s\" contains devices that you haven't seen before.": "\"%(RoomName)s\" contains devices that you haven't seen before.",
"Unknown devices": "Unknown devices",
+ "Secure your encrypted message history with a Recovery Passphrase.": "Secure your encrypted message history with a Recovery Passphrase.",
+ "You'll need it if you log out or lose access to this device.": "You'll need it if you log out or lose access to this device.",
+ "Enter a passphrase...": "Enter a passphrase...",
+ "Next": "Next",
+ "If you don't want encrypted message history to be availble on other devices, .": "If you don't want encrypted message history to be availble on other devices, .",
+ "Or, if you don't want to create a Recovery Passphrase, skip this step and .": "Or, if you don't want to create a Recovery Passphrase, skip this step and .",
+ "That matches!": "That matches!",
+ "That doesn't match.": "That doesn't match.",
+ "Go back to set it again.": "Go back to set it again.",
+ "Type in your Recovery Passphrase to confirm you remember it. If it helps, add it to your password manager or store it somewhere safe.": "Type in your Recovery Passphrase to confirm you remember it. If it helps, add it to your password manager or store it somewhere safe.",
+ "Repeat your passphrase...": "Repeat your passphrase...",
+ "Make a copy of this Recovery Key and keep it safe.": "Make a copy of this Recovery Key and keep it safe.",
+ "As a safety net, you can use it to restore your encrypted message history if you forget your Recovery Passphrase.": "As a safety net, you can use it to restore your encrypted message history if you forget your Recovery Passphrase.",
+ "Your Recovery Key": "Your Recovery Key",
+ "Copy to clipboard": "Copy to clipboard",
+ "Download": "Download",
+ "I've made a copy": "I've made a copy",
+ "Your Recovery Key has been copied to your clipboard, paste it to:": "Your Recovery Key has been copied to your clipboard, paste it to:",
+ "Your Recovery Key is in your Downloads folder.": "Your Recovery Key is in your Downloads folder.",
+ "Print it and store it somewhere safe": "Print it and store it somewhere safe",
+ "Save it on a USB key or backup drive": "Save it on a USB key or backup drive",
+ "Copy it to your personal cloud storage": "Copy it to your personal cloud storage",
+ "Got it": "Got it",
+ "Backup created": "Backup created",
+ "Your encryption keys are now being backed up to your Homeserver.": "Your encryption keys are now being backed up to your Homeserver.",
+ "Without setting up Secure Message Recovery, you won't be able to restore your encrypted message history if you log out or use another device.": "Without setting up Secure Message Recovery, you won't be able to restore your encrypted message history if you log out or use another device.",
+ "Set up Secure Message Recovery": "Set up Secure Message Recovery",
+ "Create a Recovery Passphrase": "Create a Recovery Passphrase",
+ "Confirm Recovery Passphrase": "Confirm Recovery Passphrase",
+ "Recovery Key": "Recovery Key",
+ "Keep it safe": "Keep it safe",
+ "Backing up...": "Backing up...",
+ "Create Key Backup": "Create Key Backup",
+ "Unable to create key backup": "Unable to create key backup",
+ "Retry": "Retry",
+ "Unable to load backup status": "Unable to load backup status",
+ "Unable to restore backup": "Unable to restore backup",
+ "No backup found!": "No backup found!",
+ "Backup Restored": "Backup Restored",
+ "Failed to decrypt %(failedCount)s sessions!": "Failed to decrypt %(failedCount)s sessions!",
+ "Restored %(sessionCount)s session keys": "Restored %(sessionCount)s session keys",
+ "Enter Recovery Passphrase": "Enter Recovery Passphrase",
+ "Access your secure message history and set up secure messaging by entering your recovery passphrase.": "Access your secure message history and set up secure messaging by entering your recovery passphrase.",
+ "If you've forgotten your recovery passphrase you can use your recovery key or set up new recovery options": "If you've forgotten your recovery passphrase you can use your recovery key or set up new recovery options",
+ "Enter Recovery Key": "Enter Recovery Key",
+ "This looks like a valid recovery key!": "This looks like a valid recovery key!",
+ "Not a valid recovery key": "Not a valid recovery key",
+ "Access your secure message history and set up secure messaging by entering your recovery key.": "Access your secure message history and set up secure messaging by entering your recovery key.",
+ "If you've forgotten your recovery passphrase you can ": "If you've forgotten your recovery passphrase you can ",
"Private Chat": "Private Chat",
"Public Chat": "Public Chat",
"Custom": "Custom",
@@ -1151,6 +1218,7 @@
"Autocomplete Delay (ms):": "Autocomplete Delay (ms):",
"": "",
"Import E2E room keys": "Import E2E room keys",
+ "Key Backup": "Key Backup",
"Cryptography": "Cryptography",
"Device ID:": "Device ID:",
"Device key:": "Device key:",
diff --git a/src/settings/Settings.js b/src/settings/Settings.js
index d65303b7c6..eb702a729c 100644
--- a/src/settings/Settings.js
+++ b/src/settings/Settings.js
@@ -90,6 +90,12 @@ export const SETTINGS = {
controller: new LazyLoadingController(),
default: true,
},
+ "feature_keybackup": {
+ isFeature: true,
+ displayName: _td("Backup of encryption keys to server"),
+ supportedLevels: LEVELS_FEATURE,
+ default: false,
+ },
"MessageComposerInput.dontSuggestEmoji": {
supportedLevels: LEVELS_ACCOUNT_SETTINGS,
displayName: _td('Disable Emoji suggestions while typing'),