From 47f303dc9d506295f7e66bd84551c2d3138f35d3 Mon Sep 17 00:00:00 2001 From: David Baker Date: Mon, 7 Jan 2019 10:08:57 +0000 Subject: [PATCH 1/3] Make logout warning nag about key backups https://github.com/vector-im/riot-web/issues/7805 --- src/components/views/dialogs/LogoutDialog.js | 129 ++++++++++++++++--- src/i18n/strings/en_EN.json | 6 +- 2 files changed, 115 insertions(+), 20 deletions(-) diff --git a/src/components/views/dialogs/LogoutDialog.js b/src/components/views/dialogs/LogoutDialog.js index 3c4872188a..3f0d1eb641 100644 --- a/src/components/views/dialogs/LogoutDialog.js +++ b/src/components/views/dialogs/LogoutDialog.js @@ -1,5 +1,5 @@ /* -Copyright 2018 New Vector Ltd +Copyright 2018, 2019 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. @@ -15,17 +15,44 @@ limitations under the License. */ import React from 'react'; -import QuestionDialog from './QuestionDialog'; import Modal from '../../../Modal'; +import sdk from '../../../index'; import dis from '../../../dispatcher'; import { _t } from '../../../languageHandler'; import MatrixClientPeg from '../../../MatrixClientPeg'; +import SettingsStore from "../../../settings/SettingsStore"; export default (props) => { - const description = _t("For security, logging out will delete any end-to-end " + - "encryption keys from this browser. If you want to be able " + - "to decrypt your conversation history from future Riot sessions, " + - "please export your room keys for safe-keeping."); + const onSettingsLinkClick = () => { + // close dialog + if (props.onFinished) { + props.onFinished(); + } + }; + + let description; + if (SettingsStore.isFeatureEnabled("feature_keybackup")) { + description =
+

{_t( + "When you log out, you'll lose your secure message history. To prevent " + + "this, set up a recovery method." + )}

+

{_t( + "Alternatively, advanced users can also manually export encryption keys in " + + "Settings before logging out.", {}, + { + a: sub => {sub}, + } + )}

+
; + } else { + description =
{_t( + "For security, logging out will delete any end-to-end " + + "encryption keys from this browser. If you want to be able " + + "to decrypt your conversation history from future Riot sessions, " + + "please export your room keys for safe-keeping.", + )}
; + } const onExportE2eKeysClicked = () => { Modal.createTrackedDialogAsync('Export E2E Keys', '', @@ -46,17 +73,81 @@ export default (props) => { } }; - return ({description}} - button={_t("Sign out")} - extraButtons={[ - (), - ]} - onFinished={onFinished} - />); + const onSetRecoveryMethodClick = () => { + Modal.createTrackedDialogAsync('Key Backup', 'Key Backup', + import('../../../async-components/views/dialogs/keybackup/CreateKeyBackupDialog'), + ); + + // close dialog + if (props.onFinished) { + props.onFinished(); + } + }; + + const onLogoutConfirm = () => { + dis.dispatch({action: 'logout'}); + + // close dialog + if (props.onFinished) { + props.onFinished(); + } + }; + + if (SettingsStore.isFeatureEnabled("feature_keybackup")) { + if (!MatrixClientPeg.get().getKeyBackupEnabled()) { + const BaseDialog = sdk.getComponent('views.dialogs.BaseDialog'); + const DialogButtons = sdk.getComponent('views.elements.DialogButtons'); + // Not quite a standard question dialog as the primary button cancels + // the action and does something else instead, whilst non-default button + // confirms the action. + return ( +
+ { description } +
+ + + +
); + } else { + const QuestionDialog = sdk.getComponent('views.dialogs.QuestionDialog'); + return (); + } + } else { + const QuestionDialog = sdk.getComponent('views.dialogs.QuestionDialog'); + return ( + { _t("Export E2E room keys") } + ), + ]} + onFinished={onFinished} + />); + } }; diff --git a/src/i18n/strings/en_EN.json b/src/i18n/strings/en_EN.json index 85cb8c9868..ef1b2e9162 100644 --- a/src/i18n/strings/en_EN.json +++ b/src/i18n/strings/en_EN.json @@ -967,7 +967,12 @@ "Clear cache and resync": "Clear cache and resync", "Riot now uses 3-5x less memory, by only loading information about other users when needed. Please wait whilst we resynchronise with the server!": "Riot now uses 3-5x less memory, by only loading information about other users when needed. Please wait whilst we resynchronise with the server!", "Updating Riot": "Updating Riot", + "When you log out, you'll lose your secure message history. To prevent this, set up a recovery method.": "When you log out, you'll lose your secure message history. To prevent this, set up a recovery method.", + "Alternatively, advanced users can also manually export encryption keys in Settings before logging out.": "Alternatively, advanced users can also manually export encryption keys in Settings before logging out.", "For security, logging out will delete any end-to-end encryption keys from this browser. If you want to be able to decrypt your conversation history from future Riot sessions, please export your room keys for safe-keeping.": "For security, logging out will delete any end-to-end encryption keys from this browser. If you want to be able to decrypt your conversation history from future Riot sessions, please export your room keys for safe-keeping.", + "Set a Recovery Method": "Set a Recovery Method", + "I understand, log out without": "I understand, log out without", + "When signing in again, you can access encrypted chat history by restoring your key backup. You'll need your recovery key.": "When signing in again, you can access encrypted chat history by restoring your key backup. You'll need your recovery key.", "Thanks for testing the Riot Redesign. If you run into any bugs or visual issues, please let us know on GitHub.": "Thanks for testing the Riot Redesign. If you run into any bugs or visual issues, please let us know on GitHub.", "To help avoid duplicate issues, please view existing issues first (and add a +1) or create a new issue if you can't find it.": "To help avoid duplicate issues, please view existing issues first (and add a +1) or create a new issue if you can't find it.", "Report bugs & give feedback": "Report bugs & give feedback", @@ -1376,7 +1381,6 @@ "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", From 522dddbd13dd6a643e72ed1c30894f27221c7bd6 Mon Sep 17 00:00:00 2001 From: David Baker Date: Mon, 7 Jan 2019 10:13:02 +0000 Subject: [PATCH 2/3] Lint --- src/components/views/dialogs/LogoutDialog.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/components/views/dialogs/LogoutDialog.js b/src/components/views/dialogs/LogoutDialog.js index 3f0d1eb641..604a84394e 100644 --- a/src/components/views/dialogs/LogoutDialog.js +++ b/src/components/views/dialogs/LogoutDialog.js @@ -35,14 +35,14 @@ export default (props) => { description =

{_t( "When you log out, you'll lose your secure message history. To prevent " + - "this, set up a recovery method." + "this, set up a recovery method.", )}

{_t( "Alternatively, advanced users can also manually export encryption keys in " + "Settings before logging out.", {}, { a: sub => {sub}, - } + }, )}

; } else { From 8fbb0607ffe569b1bd02047f5b95ad66c21debfe Mon Sep 17 00:00:00 2001 From: David Baker Date: Mon, 7 Jan 2019 12:09:19 +0000 Subject: [PATCH 3/3] Re-write as full class component So we can re-use the functions we pass to props --- package.json | 2 +- src/components/views/dialogs/LogoutDialog.js | 193 ++++++++++--------- 2 files changed, 103 insertions(+), 92 deletions(-) diff --git a/package.json b/package.json index 6dc9a6bfcf..155d3d1b23 100644 --- a/package.json +++ b/package.json @@ -47,7 +47,7 @@ "start:init": "babel src -d lib --source-maps --copy-files", "lint": "eslint src/", "lintall": "eslint src/ test/", - "lintwithexclusions": "eslint --max-warnings 20 --ignore-path .eslintignore.errorfiles src test", + "lintwithexclusions": "eslint --max-warnings 16 --ignore-path .eslintignore.errorfiles src test", "clean": "rimraf lib", "prepublish": "npm run clean && npm run build && git rev-parse HEAD > git-revision.txt", "test": "karma start --single-run=true --browsers ChromeHeadless", diff --git a/src/components/views/dialogs/LogoutDialog.js b/src/components/views/dialogs/LogoutDialog.js index 604a84394e..8c74b3aff5 100644 --- a/src/components/views/dialogs/LogoutDialog.js +++ b/src/components/views/dialogs/LogoutDialog.js @@ -22,132 +22,143 @@ import { _t } from '../../../languageHandler'; import MatrixClientPeg from '../../../MatrixClientPeg'; import SettingsStore from "../../../settings/SettingsStore"; -export default (props) => { - const onSettingsLinkClick = () => { - // close dialog - if (props.onFinished) { - props.onFinished(); - } - }; - - let description; - if (SettingsStore.isFeatureEnabled("feature_keybackup")) { - description =
-

{_t( - "When you log out, you'll lose your secure message history. To prevent " + - "this, set up a recovery method.", - )}

-

{_t( - "Alternatively, advanced users can also manually export encryption keys in " + - "Settings before logging out.", {}, - { - a: sub => {sub}, - }, - )}

-
; - } else { - description =
{_t( - "For security, logging out will delete any end-to-end " + - "encryption keys from this browser. If you want to be able " + - "to decrypt your conversation history from future Riot sessions, " + - "please export your room keys for safe-keeping.", - )}
; +export default class LogoutDialog extends React.Component { + constructor() { + super(); + this._onSettingsLinkClick = this._onSettingsLinkClick.bind(this); + this._onExportE2eKeysClicked = this._onExportE2eKeysClicked.bind(this); + this._onFinished = this._onFinished.bind(this); + this._onSetRecoveryMethodClick = this._onSetRecoveryMethodClick.bind(this); + this._onLogoutConfirm = this._onLogoutConfirm.bind(this); } - const onExportE2eKeysClicked = () => { + _onSettingsLinkClick() { + // close dialog + if (this.props.onFinished) { + this.props.onFinished(); + } + } + + _onExportE2eKeysClicked() { Modal.createTrackedDialogAsync('Export E2E Keys', '', import('../../../async-components/views/dialogs/ExportE2eKeysDialog'), { matrixClient: MatrixClientPeg.get(), }, ); - }; + } - const onFinished = (confirmed) => { + _onFinished(confirmed) { if (confirmed) { dis.dispatch({action: 'logout'}); } // close dialog - if (props.onFinished) { - props.onFinished(); + if (this.props.onFinished) { + this.props.onFinished(); } - }; + } - const onSetRecoveryMethodClick = () => { + _onSetRecoveryMethodClick() { Modal.createTrackedDialogAsync('Key Backup', 'Key Backup', import('../../../async-components/views/dialogs/keybackup/CreateKeyBackupDialog'), ); // close dialog - if (props.onFinished) { - props.onFinished(); + if (this.props.onFinished) { + this.props.onFinished(); } - }; + } - const onLogoutConfirm = () => { + _onLogoutConfirm() { dis.dispatch({action: 'logout'}); // close dialog - if (props.onFinished) { - props.onFinished(); + if (this.props.onFinished) { + this.props.onFinished(); } - }; + } - if (SettingsStore.isFeatureEnabled("feature_keybackup")) { - if (!MatrixClientPeg.get().getKeyBackupEnabled()) { - const BaseDialog = sdk.getComponent('views.dialogs.BaseDialog'); - const DialogButtons = sdk.getComponent('views.elements.DialogButtons'); - // Not quite a standard question dialog as the primary button cancels - // the action and does something else instead, whilst non-default button - // confirms the action. - return ( -
- { description } -
- +

{_t( + "When you log out, you'll lose your secure message history. To prevent " + + "this, set up a recovery method.", + )}

+

{_t( + "Alternatively, advanced users can also manually export encryption keys in " + + "Settings before logging out.", {}, + { + a: sub => {sub}, + }, + )}

+ ; + } else { + description =
{_t( + "For security, logging out will delete any end-to-end " + + "encryption keys from this browser. If you want to be able " + + "to decrypt your conversation history from future Riot sessions, " + + "please export your room keys for safe-keeping.", + )}
; + } + + if (SettingsStore.isFeatureEnabled("feature_keybackup")) { + if (!MatrixClientPeg.get().getKeyBackupEnabled()) { + const BaseDialog = sdk.getComponent('views.dialogs.BaseDialog'); + const DialogButtons = sdk.getComponent('views.elements.DialogButtons'); + // Not quite a standard question dialog as the primary button cancels + // the action and does something else instead, whilst non-default button + // confirms the action. + return ( - -
-
); +
+ { description } +
+ + + + ); + } else { + const QuestionDialog = sdk.getComponent('views.dialogs.QuestionDialog'); + return (); + } } else { const QuestionDialog = sdk.getComponent('views.dialogs.QuestionDialog'); return ( + { _t("Export E2E room keys") } + ), + ]} + onFinished={this._onFinished} />); } - } else { - const QuestionDialog = sdk.getComponent('views.dialogs.QuestionDialog'); - return ( - { _t("Export E2E room keys") } - ), - ]} - onFinished={onFinished} - />); } -}; +}