Skip to content

Commit

Permalink
Notify user when crypto data is missing
Browse files Browse the repository at this point in the history
If we have account data in local storage but nothing in the crypto store, it
generally means the browser has evicted IndexedDB out from under us. This adds a
modal to explain the situation and offer to completely clear storage to get
things back to normal.

Fixes element-hq/element-web#9109
  • Loading branch information
jryans committed Mar 28, 2019
1 parent 1ae429f commit 77c1166
Show file tree
Hide file tree
Showing 5 changed files with 120 additions and 3 deletions.
20 changes: 19 additions & 1 deletion src/Lifecycle.js
Original file line number Diff line number Diff line change
Expand Up @@ -354,7 +354,16 @@ 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 clear = await _showStorageEvictedDialog();
if (clear) {
await _clearStorage();
}
}

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

Expand Down Expand Up @@ -386,6 +395,15 @@ 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,
});
});
}

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
87 changes: 87 additions & 0 deletions src/components/views/dialogs/StorageEvictedDialog.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
/*
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 = () => {
const BugReportDialog = sdk.getComponent("dialogs.BugReportDialog");
Modal.createTrackedDialog('Storage evicted', 'Send Bug Report Dialog', BugReportDialog, {});
};

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

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

let secondaryButton;
let logRequest;
if (SdkConfig.get().bug_report_endpoint_url) {
secondaryButton = <button onClick={this._sendBugReport}>
{_t("Send Logs")}
</button>;
logRequest = <p>{_t(
"We'd like to find ways to avoid this happening in the future. " +
"If you'd like to help, please consider sending logs as well.",
)}</p>;
}

return (
<BaseDialog className="mx_ErrorDialog" onFinished={this.props.onFinished}
title={_t('Some session data is missing')}
contentId='mx_Dialog_content'
hasCancel={false}
>
<div className="mx_Dialog_content" id='mx_Dialog_content'>
<p>{_t(
"Riot noticed that some session data, including encrypted " +
"message keys, is missing from this device.",
)}</p>
<p>{_t(
"Some browsers may remove this data without telling you or " +
"Riot when your device is running low on free disk space.",
)}</p>
<p>{_t(
"We recommend that you allow Riot to clear and rebuild " +
"your session data. If you previously enabled Secure " +
"Message Recovery, your encrypted message keys will be " +
"restored from the most recent backup.",
) }</p>
{logRequest}
</div>
<DialogButtons primaryButton={_t("Clear and Rebuild Storage")}
onPrimaryButtonClick={this._onSignOutClick}
focus={true}
hasCancel={false}
>
{ secondaryButton }
</DialogButtons>
</BaseDialog>
);
}
}
8 changes: 7 additions & 1 deletion src/i18n/strings/en_EN.json
Original file line number Diff line number Diff line change
Expand Up @@ -1141,7 +1141,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 @@ -1177,6 +1177,12 @@
"Share Room Message": "Share Room Message",
"Link to selected message": "Link to selected message",
"COPY": "COPY",
"We'd like to find ways to avoid this happening in the future. If you'd like to help, please consider sending logs as well.": "We'd like to find ways to avoid this happening in the future. If you'd like to help, please consider sending logs as well.",
"Some session data is missing": "Some session data is missing",
"Riot noticed that some session data, including encrypted message keys, is missing from this device.": "Riot noticed that some session data, including encrypted message keys, is missing from this device.",
"Some browsers may remove this data without telling you or Riot when your device is running low on free disk space.": "Some browsers may remove this data without telling you or Riot when your device is running low on free disk space.",
"We recommend that you allow Riot to clear and rebuild your session data. If you previously enabled Secure Message Recovery, your encrypted message keys will be restored from the most recent backup.": "We recommend that you allow Riot to clear and rebuild your session data. If you previously enabled Secure Message Recovery, your encrypted message keys will be restored from the most recent backup.",
"Clear and Rebuild Storage": "Clear and Rebuild Storage",
"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 @@ -110,4 +110,10 @@ export async function checkConsistency() {
error("Storage consistency checks failed");
track("Consistency checks failed");
}

return {
dataInLocalStorage,
dataInCryptoStore,
healthy,
};
}

0 comments on commit 77c1166

Please sign in to comment.