Skip to content

Commit

Permalink
Merge pull request #2841 from jryans/storage-eviction-modal
Browse files Browse the repository at this point in the history
Notify user when crypto data is missing
  • Loading branch information
jryans committed Apr 1, 2019
2 parents f3e8722 + 328f0cd commit 57d72b4
Show file tree
Hide file tree
Showing 8 changed files with 154 additions and 9 deletions.
21 changes: 19 additions & 2 deletions .babelrc
Original file line number Diff line number Diff line change
@@ -1,4 +1,21 @@
{
"presets": ["react", "es2015", "es2016"],
"plugins": ["transform-class-properties", "transform-object-rest-spread", "transform-async-to-bluebird", "transform-runtime", "add-module-exports", "syntax-dynamic-import"]
"presets": [
"react",
"es2015",
"es2016"
],
"plugins": [
[
"transform-builtin-extend",
{
"globals": ["Error"]
}
],
"transform-class-properties",
"transform-object-rest-spread",
"transform-async-to-bluebird",
"transform-runtime",
"add-module-exports",
"syntax-dynamic-import"
]
}
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,7 @@
"babel-loader": "^7.1.5",
"babel-plugin-add-module-exports": "^0.2.1",
"babel-plugin-transform-async-to-bluebird": "^1.1.1",
"babel-plugin-transform-builtin-extend": "^1.1.2",
"babel-plugin-transform-class-properties": "^6.24.1",
"babel-plugin-transform-object-rest-spread": "^6.26.0",
"babel-plugin-transform-runtime": "^6.23.0",
Expand Down
38 changes: 35 additions & 3 deletions src/Lifecycle.js
Original file line number Diff line number Diff line change
Expand Up @@ -103,9 +103,14 @@ export async function loadSession(opts) {
return _registerAsGuest(guestHsUrl, guestIsUrl, defaultDeviceDisplayName);
}

// fall back to login screen
// fall back to welcome screen
return false;
} catch (e) {
if (e instanceof AbortLoginAndRebuildStorage) {
// If we're aborting login because of a storage inconsistency, we don't
// need to show the general failure dialog. Instead, just go back to welcome.
return false;
}
return _handleLoadSessionFailure(e);
}
}
Expand Down Expand Up @@ -279,7 +284,7 @@ async function _restoreFromLocalStorage() {
}

function _handleLoadSessionFailure(e) {
console.log("Unable to load session", e);
console.error("Unable to load session", e);

const def = Promise.defer();
const SessionRestoreErrorDialog =
Expand Down Expand Up @@ -354,7 +359,21 @@ async function _doSetLoggedIn(credentials, clearStorage) {
await _clearStorage();
}

await StorageManager.checkConsistency();
const results = await StorageManager.checkConsistency();
// If there's an inconsistency between account data in local storage and the
// crypto store, we'll be generally confused when handling encrypted data.
// Show a modal recommending a full reset of storage.
if (results.dataInLocalStorage && !results.dataInCryptoStore) {
const signOut = await _showStorageEvictedDialog();
if (signOut) {
await _clearStorage();
// This error feels a bit clunky, but we want to make sure we don't go any
// further and instead head back to sign in.
throw new AbortLoginAndRebuildStorage(
"Aborting login in progress because of storage inconsistency",
);
}
}

Analytics.setLoggedIn(credentials.guest, credentials.homeserverUrl, credentials.identityServerUrl);

Expand Down Expand Up @@ -386,6 +405,19 @@ async function _doSetLoggedIn(credentials, clearStorage) {
return MatrixClientPeg.get();
}

function _showStorageEvictedDialog() {
const StorageEvictedDialog = sdk.getComponent('views.dialogs.StorageEvictedDialog');
return new Promise(resolve => {
Modal.createTrackedDialog('Storage evicted', '', StorageEvictedDialog, {
onFinished: resolve,
});
});
}

// Note: Babel 6 requires the `transform-builtin-extend` plugin for this to satisfy
// `instanceof`. Babel 7 supports this natively in their class handling.
class AbortLoginAndRebuildStorage extends Error { }

function _persistCredentialsToLocalStorage(credentials) {
localStorage.setItem("mx_hs_url", credentials.homeserverUrl);
localStorage.setItem("mx_is_url", credentials.identityServerUrl);
Expand Down
2 changes: 1 addition & 1 deletion src/components/views/dialogs/SessionRestoreErrorDialog.js
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ export default React.createClass({
Modal.createTrackedDialog('Session Restore Confirm Logout', '', QuestionDialog, {
title: _t("Sign out"),
description:
<div>{ _t("Log out and remove encryption keys?") }</div>,
<div>{ _t("Sign out and remove encryption keys?") }</div>,
button: _t("Sign out"),
danger: true,
onFinished: this.props.onFinished,
Expand Down
77 changes: 77 additions & 0 deletions src/components/views/dialogs/StorageEvictedDialog.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
/*
Copyright 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.
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 React from 'react';
import PropTypes from 'prop-types';
import sdk from '../../../index';
import SdkConfig from '../../../SdkConfig';
import Modal from '../../../Modal';
import { _t } from '../../../languageHandler';

export default class StorageEvictedDialog extends React.Component {
static propTypes = {
onFinished: PropTypes.func.isRequired,
};

_sendBugReport = ev => {
ev.preventDefault();
const BugReportDialog = sdk.getComponent("dialogs.BugReportDialog");
Modal.createTrackedDialog('Storage evicted', 'Send Bug Report Dialog', BugReportDialog, {});
};

_onSignOutClick = () => {
this.props.onFinished(true);
};

render() {
const BaseDialog = sdk.getComponent('views.dialogs.BaseDialog');
const DialogButtons = sdk.getComponent('views.elements.DialogButtons');

let logRequest;
if (SdkConfig.get().bug_report_endpoint_url) {
logRequest = _t(
"To help us prevent this in future, please <a>send us logs</a>.", {},
{
a: text => <a href="#" onClick={this._sendBugReport}>{text}</a>,
});
}

return (
<BaseDialog className="mx_ErrorDialog" onFinished={this.props.onFinished}
title={_t('Missing session data')}
contentId='mx_Dialog_content'
hasCancel={false}
>
<div className="mx_Dialog_content" id='mx_Dialog_content'>
<p>{_t(
"Some session data, including encrypted message keys, is " +
"missing. Sign out and sign in to fix this, restoring keys " +
"from backup.",
)}</p>
<p>{_t(
"Your browser likely removed this data when running low on " +
"disk space.",
)} {logRequest}</p>
</div>
<DialogButtons primaryButton={_t("Sign out")}
onPrimaryButtonClick={this._onSignOutClick}
focus={true}
hasCancel={false}
/>
</BaseDialog>
);
}
}
6 changes: 5 additions & 1 deletion src/i18n/strings/en_EN.json
Original file line number Diff line number Diff line change
Expand Up @@ -1146,7 +1146,7 @@
"Update any local room aliases to point to the new room": "Update any local room aliases to point to the new room",
"Stop users from speaking in the old version of the room, and post a message advising users to move to the new room": "Stop users from speaking in the old version of the room, and post a message advising users to move to the new room",
"Put a link back to the old room at the start of the new room so people can see old messages": "Put a link back to the old room at the start of the new room so people can see old messages",
"Log out and remove encryption keys?": "Log out and remove encryption keys?",
"Sign out and remove encryption keys?": "Sign out and remove encryption keys?",
"Clear Storage and Sign Out": "Clear Storage and Sign Out",
"Send Logs": "Send Logs",
"Refresh": "Refresh",
Expand Down Expand Up @@ -1182,6 +1182,10 @@
"Share Room Message": "Share Room Message",
"Link to selected message": "Link to selected message",
"COPY": "COPY",
"To help us prevent this in future, please <a>send us logs</a>.": "To help us prevent this in future, please <a>send us logs</a>.",
"Missing session data": "Missing session data",
"Some session data, including encrypted message keys, is missing. Sign out and sign in to fix this, restoring keys from backup.": "Some session data, including encrypted message keys, is missing. Sign out and sign in to fix this, restoring keys from backup.",
"Your browser likely removed this data when running low on disk space.": "Your browser likely removed this data when running low on disk space.",
"Error showing you your room": "Error showing you your room",
"Riot has run into a problem which makes it difficult to show you your messages right now. Nothing has been lost and reloading the app should fix this for you. In order to assist us in troubleshooting the problem, we'd like to take a look at your debug logs. You do not need to send your logs unless you want to, but we would really appreciate it if you did. We'd also like to apologize for having to show this message to you - we hope your debug logs are the key to solving the issue once and for all. If you'd like more information on the bug you've accidentally run into, please visit <a>the issue</a>.": "Riot has run into a problem which makes it difficult to show you your messages right now. Nothing has been lost and reloading the app should fix this for you. In order to assist us in troubleshooting the problem, we'd like to take a look at your debug logs. You do not need to send your logs unless you want to, but we would really appreciate it if you did. We'd also like to apologize for having to show this message to you - we hope your debug logs are the key to solving the issue once and for all. If you'd like more information on the bug you've accidentally run into, please visit <a>the issue</a>.",
"Send debug logs and reload Riot": "Send debug logs and reload Riot",
Expand Down
6 changes: 6 additions & 0 deletions src/utils/StorageManager.js
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,12 @@ export async function checkConsistency() {
error("Storage consistency checks failed");
track("Consistency checks failed");
}

return {
dataInLocalStorage,
dataInCryptoStore,
healthy,
};
}

async function checkSyncStore() {
Expand Down
12 changes: 10 additions & 2 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -902,6 +902,14 @@ babel-plugin-transform-async-to-generator@^6.24.1:
babel-plugin-syntax-async-functions "^6.8.0"
babel-runtime "^6.22.0"

babel-plugin-transform-builtin-extend@^1.1.2:
version "1.1.2"
resolved "https://registry.yarnpkg.com/babel-plugin-transform-builtin-extend/-/babel-plugin-transform-builtin-extend-1.1.2.tgz#5e96fecf58b8fa1ed74efcad88475b2af3c9116e"
integrity sha1-Xpb+z1i4+h7XTvytiEdbKvPJEW4=
dependencies:
babel-runtime "^6.2.0"
babel-template "^6.3.0"

babel-plugin-transform-class-properties@^6.24.1:
version "6.24.1"
resolved "https://registry.yarnpkg.com/babel-plugin-transform-class-properties/-/babel-plugin-transform-class-properties-6.24.1.tgz#6a79763ea61d33d36f37b611aa9def81a81b46ac"
Expand Down Expand Up @@ -1267,15 +1275,15 @@ babel-register@^6.26.0:
mkdirp "^0.5.1"
source-map-support "^0.4.15"

babel-runtime@^6.18.0, babel-runtime@^6.22.0, babel-runtime@^6.26.0:
babel-runtime@^6.18.0, babel-runtime@^6.2.0, babel-runtime@^6.22.0, babel-runtime@^6.26.0:
version "6.26.0"
resolved "https://registry.yarnpkg.com/babel-runtime/-/babel-runtime-6.26.0.tgz#965c7058668e82b55d7bfe04ff2337bc8b5647fe"
integrity sha1-llxwWGaOgrVde/4E/yM3vItWR/4=
dependencies:
core-js "^2.4.0"
regenerator-runtime "^0.11.0"

babel-template@^6.24.1, babel-template@^6.26.0, babel-template@^6.9.0:
babel-template@^6.24.1, babel-template@^6.26.0, babel-template@^6.3.0, babel-template@^6.9.0:
version "6.26.0"
resolved "https://registry.yarnpkg.com/babel-template/-/babel-template-6.26.0.tgz#de03e2d16396b069f46dd9fff8521fb1a0e35e02"
integrity sha1-3gPi0WOWsGn0bdn/+FIfsaDjXgI=
Expand Down

0 comments on commit 57d72b4

Please sign in to comment.